ここまではglVertexで三角形を描画してきたが、ここで配列からデータ投入して連続した三角形を描画する方法を導入する。 頂点データを格納した配列を頂点配列(VertexArray)と呼ぶ。
#!/usr/bin/python
# coding: utf-8
from OpenGL.GL import *
'''
頂点配列
====
属性
====
* 位置
'''
class VertexArray(object):
def __init__(self, vertices):
self.vertices=vertices
def __str__(self):
return "<VertexArray %d>" % len(self.vertices)
def draw(self):
# 位置属性
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertices)
# 描画
glDrawArrays(GL_TRIANGLES, 0, len(self.vertices))
# 後始末
glDisableClientState(GL_VERTEX_ARRAY)
'''
頂点配列
====
属性
====
* 位置
* UV
'''
class VertexArrayWithUV(object):
def __init__(self, vertices, uvarray):
self.vertices=vertices
self.uvarray=uvarray
def __str__(self):
return "<VertexArrayWithUV %d>" % len(self.vertices)
def draw(self):
# 位置属性
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertices)
# UV属性
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glTexCoordPointer(2, GL_FLOAT, 0, self.uvarray)
# 描画
glDrawArrays(GL_TRIANGLES, 0, len(self.vertices))
# 後始末
glDisableClientState(GL_TEXTURE_COORD_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY)
'''
インデックス参照頂点配列
====
属性
====
* 位置
'''
class IndexedVertexArray(object):
def __init__(self, vertices, indices):
self.vertices=vertices
self.indices=indices
def draw(self):
# 位置属性
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertices)
# indexによる描画
glDrawElements(GL_TRIANGLES, len(self.indices),
GL_UNSIGNED_INT, self.indices)
# 後始末
glDisableClientState(GL_VERTEX_ARRAY)
'''
インデックス参照頂点配列
====
属性
====
* 位置
* 色
'''
class IndexedVertexArrayWithColor(object):
def __init__(self, vertices, colors, indices):
self.vertices=vertices
self.colors=colors
self.indices=indices
def draw(self):
# 位置属性
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertices)
# 色属性
glEnableClientState(GL_COLOR_ARRAY)
glColorPointer(3, GL_FLOAT, 0, self.colors)
# indexによる描画
glDrawElements(GL_TRIANGLES, len(self.indices),
GL_UNSIGNED_INT, self.indices)
# 後始末
glDisableClientState(GL_COLOR_ARRAY)
glDisableClientState(GL_VERTEX_ARRAY)
頂点配列の保持と描画はこれだけで、むしろ glBegin()~glVertex()~glEnd() の呼び出しよりシンプルなくらいになる。 問題は、如何にこの配列にデータを満たすのかということになる。
OpenGLの頂点について軽く説明。
OpenGLの頂点は、三次元空間上の座標をもった点で座標以外にも複数の属性を持つことができる。以下、各属性について
必須の属性で(x, y, z, w)。三次元の同次座標表現(アフィン変換用)となっている。 モデルビュー座標を操作している間は、基本的にw=1なのでw値を意識する必要は無い。
透視投影で遠近感の処理をするときに、wが1以外になる。視点から遠い点ほどwが大きくなるように仕込んでから、wが1になるように(x, y, z, w)をわる(同時座標の正規化)ことで遠近感を表現することができる。
頂点カラー。隣の点と色が違う場合にグラデーションを作れる。
UV座標。テクスチャを貼るときに使う。
サンプルとして頂点配列で立方体を描画する。 立方体は、各面に2つずつ三角形が含まれるので12の三角形を含む。 glVertexだと36回呼び出しが必要となる(GL_TRIANGLESを使う場合)ところを、 頂点配列を使ってサクッと描画する。 面倒なところが、描画時から初期化時に移ることになる。
#!/usr/bin/python
# coding: utf8
from OpenGL.GL import *
import glut_ui
import glbase
import vertexarray
def createCube(size):
return vertexarray.IndexedVertexArrayWithColor(
vertices=[
-size, -size, -size, # v0
size, -size, -size, # v1
size, size, -size, # v2
-size, size, -size, # v3
-size, -size, size, # v4
size, -size, size, # v5
size, size, size, # v6
-size, size, size, # v7
],
colors=[
1, 0, 0, # v0の色
0, 1, 0, # v1の色
0, 0, 1, # v2の色
1, 1, 1, # v3の色
0, 1, 1, # v4の色
1, 0, 1, # v5の色
1, 1, 0, # v6の色
0, 0, 0, # v7の色
],
indices=[
4, 5, 6, # triangle0の頂点index
6, 7, 4, # triangle1の頂点index
5, 1, 2, # triangle2の頂点index
2, 6, 5, # triangle3の頂点index
1, 0, 3, # triangle4の頂点index
3, 2, 1, # triangle5の頂点index
0, 4, 7, # triangle6の頂点index
7, 3, 0, # triangle7の頂点index
3, 7, 6, # triangle8の頂点index
6, 2, 3, # triangle9の頂点index
0, 1, 5, # triangle10の頂点index
5, 4, 0, # triangle11の頂点index
])
if __name__=="__main__":
import Rotation
glut_ui.run(glbase.BaseController(Rotation.Rotation(), createCube(0.4)))