前の記事で、PythonでOpenGLを操作する基本について説明しました。 グラフィックを表示するために、glutモジュールの組み込み関数とシェーダーなしの固定OpenGLパイプラインが使用されました。 前のレッスンに基づいて、habrahabr.ruユーザーのリクエストにより、シェーダーとバッファーオブジェクトを使用してPyOpenGLアプリケーションテンプレートが作成されました。
前の記事のように、豪華なグラフィックスは期待できません。 この記事の目的は、PyOpenGLモジュールを使用してシェーダーとバッファーオブジェクトを操作する機能を示すことです。
したがって、仕事には次のものが必要です。
開発環境で、Pythonコードを使用して新しいファイルを作成して保存します。
3Dグラフィックス(特にOpenGL)を使用するには、いくつかのモジュールをインポートする必要があります。
from OpenGL.GL import * from OpenGL.GLUT import *
glutモジュールを使用して、ウィンドウを作成し、キーストロークを処理します。 さらに、同じ名前のモジュールからランダム関数をインポートします(ポリゴンの色を変更するのに便利です):
from random import random
準備。
ダブルバッファリングとRGB形式の色を使用して表示モードを初期化します(ダブルバッファリングにより、画面の再描画中のちらつきを回避できます)。
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB)
初期ウィンドウサイズ(幅、高さ)を設定します。
glutInitWindowSize(300, 300)
画面の左上隅に対するウィンドウの初期位置を指定します。
glutInitWindowPosition(50, 50)
OpenGlを初期化しましょう:
glutInit(sys.argv)
タイトルが「Shaders!」のウィンドウを作成します。
glutCreateWindow(b"Shaders!")
画面にグラフィックを表示する手順を定義します。
glutDisplayFunc(draw)
「単純な」プログラムで実行される手順を定義します。
glutIdleFunc(draw)
特別なキーを処理する手順を定義します。
glutSpecialFunc(specialkeys)
灰色を設定して画面をクリアします。
glClearColor(0.2, 0.2, 0.2, 1)
その瞬間まで、コードは前の記事で使用したものと実質的に区別できませんでしたが、今ではすべてが大きく変化しており、シェーダーが登場します!
便宜上、シェーダーを使用できるように準備するプロシージャを作成します。
# ( , ) def create_shader(shader_type, source): # shader = glCreateShader(shader_type) # glShaderSource(shader, source) # glCompileShader(shader) # return shader
create_shaderプロシージャを使用して、頂点シェーダーを作成します。
# # - vertex = create_shader(GL_VERTEX_SHADER, """ varying vec4 vertex_color; void main(){ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; vertex_color = gl_Color; }""")
同様に、フラグメントシェーダーを作成します。
# "" fragment = create_shader(GL_FRAGMENT_SHADER, """ varying vec4 vertex_color; void main() { gl_FragColor = vertex_color; }""")
空のシェーダープログラムオブジェクトを作成します。
program = glCreateProgram()
頂点シェーダーとフラグメントシェーダーをプログラムに接続します。
glAttachShader(program, vertex) glAttachShader(program, fragment)
シェーダープログラムの「収集」:
glLinkProgram(program)
画面にオブジェクトを表示するときに、このシェーダープログラムを使用する必要があることをOpenGLに通知します。
glUseProgram(program)
次に、表示する色と色を決定する必要があります。 これを行うには、2つの配列を作成します。 最初の配列は、頂点の座標(3つの座標の3つの頂点)です。
pointdata = [[0, 0.5, 0], [-0.5, -0.5, 0], [0.5, -0.5, 0]]
2番目の配列は、各頂点の色(それぞれに1色)があります:
pointcolor = [[1, 1, 0], [0, 1, 1], [1, 0, 1]]
これらの2つの配列は1つにまとめることができますが、わかりやすくするために間隔を空けています。 これで、準備措置が完了し、プログラムのメインサイクルを開始できます。
glutMainLoop()
次に、キーストロークを処理し、実際には画面にオブジェクトを表示する手順を検討します。
キーストロークハンドラ。
specialkeysプロシージャは、プログラムのキーストロークを処理します。 specialkeysコードでは、キーボードのどの矢印が押されたかに応じて、glRotatefプロシージャを使用して、x軸またはy軸を時計回りまたは反対方向に5度回転します。 ENDキーを押すと、pointcolor配列に0〜1の範囲の乱数を入力して、表示されるポリゴンの色を変更します。 特殊キー手順コード:
# def specialkeys(key, x, y): # pointcolor global pointcolor # if key == GLUT_KEY_UP: # glRotatef(5, 1, 0, 0) # 5 X if key == GLUT_KEY_DOWN: # glRotatef(-5, 1, 0, 0) # -5 X if key == GLUT_KEY_LEFT: # glRotatef(5, 0, 1, 0) # 5 Y if key == GLUT_KEY_RIGHT: # glRotatef(-5, 0, 1, 0) # -5 Y if key == GLUT_KEY_END: # END # pointcolor 0-1 pointcolor = [[random(), random(), random()], [random(), random(), random()], [random(), random(), random()]]
再描画手順。
再描画手順は、プログラムの再描画を担当します。 まず、画面をクリアして灰色で塗りつぶします。
glClear(GL_COLOR_BUFFER_BIT)
頂点と色の配列の使用を含めます。
glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_COLOR_ARRAY)
次に、頂点の配列を取得する場所をOpenGLに示します。これには、glVertexPointerプロシージャを使用します。
glVertexPointer(3, GL_FLOAT, 0, pointdata)
このプロシージャの最初のパラメーターは、1つの頂点に使用する座標の数を決定し、2番目のパラメーターは各座標のデータ型を決定し、3番目のパラメーターは配列内の頂点間のオフセットを決定します。 頂点が次々に進む場合、オフセットは0です。4番目のパラメーターは、配列内の最初の頂点の最初の座標を示します。
同様に、色の配列を取得するOpenGLを示します。
glColorPointer(3, GL_FLOAT, 0, pointcolor)
必要なすべてのデータが示されており、すべてを描画するためだけに残っています。 glDrawArraysプロシージャを使用して、配列の内容全体を一度に表示できます。
glDrawArrays(GL_TRIANGLES, 0, 3)
このプロシージャの最初のパラメーターは、画面上にオブジェクトを表示するときに使用するプリミティブのタイプ(三角形、ポイント、ラインなど)を決定し、2番目のパラメーターは指定された配列の初期インデックスを示し、3番目のパラメーターは描画されたプリミティブの数を示します(この場合これらは3つの頂点-9座標です)。
頂点と色の配列の使用を無効にし、メモリに描画されたすべてを画面に表示します。
glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) glutSwapBuffers()
その結果、プログラムウィンドウで、滑らかな色の遷移を伴う三角形が観察されます。 矢印キーを使用して三角形を回転できます。 ENDボタンを押すと、三角形の色がランダムに変わります。
すべてのプログラムコード:
# -*- coding: utf-8 -*- # : from OpenGL.GL import * from OpenGL.GLUT import * #import sys # random random from random import random # pointcolor ( ) global pointcolor # def specialkeys(key, x, y): # pointcolor global pointcolor # if key == GLUT_KEY_UP: # glRotatef(5, 1, 0, 0) # 5 X if key == GLUT_KEY_DOWN: # glRotatef(-5, 1, 0, 0) # -5 X if key == GLUT_KEY_LEFT: # glRotatef(5, 0, 1, 0) # 5 Y if key == GLUT_KEY_RIGHT: # glRotatef(-5, 0, 1, 0) # -5 Y if key == GLUT_KEY_END: # END # pointcolor 0-1 pointcolor = [[random(), random(), random()], [random(), random(), random()], [random(), random(), random()]] # ( , ) def create_shader(shader_type, source): # shader = glCreateShader(shader_type) # glShaderSource(shader, source) # glCompileShader(shader) # return shader # def draw(): glClear(GL_COLOR_BUFFER_BIT) # glEnableClientState(GL_VERTEX_ARRAY) # glEnableClientState(GL_COLOR_ARRAY) # # , : # - # - # - # , 0 # - glVertexPointer(3, GL_FLOAT, 0, pointdata) # , : # , glColorPointer(3, GL_FLOAT, 0, pointcolor) # : # - (, , .) # - # - ( 3 - 9 ) glDrawArrays(GL_TRIANGLES, 0, 3) glDisableClientState(GL_VERTEX_ARRAY) # glDisableClientState(GL_COLOR_ARRAY) # glutSwapBuffers() # # # RGB ( ) glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB) # (, ) glutInitWindowSize(300, 300) # # glutInitWindowPosition(50, 50) # OpenGl glutInit(sys.argv) # "Shaders!" glutCreateWindow(b"Shaders!") # , glutDisplayFunc(draw) # , "" glutIdleFunc(draw) # , glutSpecialFunc(specialkeys) # glClearColor(0.2, 0.2, 0.2, 1) # : # # - vertex = create_shader(GL_VERTEX_SHADER, """ varying vec4 vertex_color; void main(){ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; vertex_color = gl_Color; }""") # : # "" fragment = create_shader(GL_FRAGMENT_SHADER, """ varying vec4 vertex_color; void main() { gl_FragColor = vertex_color; }""") # program = glCreateProgram() # c glAttachShader(program, vertex) # glAttachShader(program, fragment) # "" glLinkProgram(program) # OpenGL glUseProgram(program) # ( ) pointdata = [[0, 0.5, 0], [-0.5, -0.5, 0], [0.5, -0.5, 0]] # ( ) pointcolor = [[1, 1, 0], [0, 1, 1], [1, 0, 1]] # glutMainLoop()
プログラムの結果(写真):
およびいくつかのビデオ: