Sample01

ここでは、OpenGLの基礎知識、二次元図形の描き方、glutを使ったウインドウの作り方を解説します。


配布物


OpenGLの基礎

OpenGLの大きな特色として、"State Machine"であることがあげられます。どういうことかと言うと、OpenGLは与えられた状態を覚えていて、コマンドが発行されると、覚えている状態をつかって実行します。例えば、色を一度指定すると、もう一度指定しなおすまでずっと同じ色で描画を行います。
毎回いろいろ指定しなくてよいので楽だしオーバーヘッドも少ないのですが、状態を意識していないと痛い目にあったりします。


OpenGL関連ライブラリの構成

How to buildでも触れたように、このページで扱うサンプルプログラムは3つのライブラリを使います。

OpenGLライブラリ(libGL.so / opengl32.dll)
OpenGLのコアの部分で、図形の描画機能や、座標変換などのAPIを提供します。APIは、gl****という"gl"で始まる名前がついています。
GLUライブラリ(libGLU.so / glu32.dll)
GL Utilityの略で(たぶん)、libGL.soには含まれない便利機能が含まれています。例えば、球や円柱を描く機能や、nurbs曲面を描く機能、ミップマップを作成する機能などが含まれます。APIは、"glu"で始まる名前が付いています。
glutライブラリ(libglut.so / glut32.dll)
glutは、ウインドウを作ったりマウスやキーボード入力を受け付けたりするユーザーインターフェイスライブラリで、ウインドウ内部の表示にOpenGLを使うというものです。APIに"glut"で始まる名前が付いています。

OpenGLのAPI命名則

OpenGLのAPIの命名則について説明します。例えば、頂点を定義するglVertex〜というAPIがありますが、この仲間は以下のようにいっぱいあります。

glVertex2d, glVertex2f, glVertex2i, glVertex2s, glVertex3d, glVertex3f, glVertex3i, glVertex3s, glVertex4d, glVertex4f, glVertex4i, glVertex4s, glVertex2dv, glVertex2fv, glVertex2iv, glVertex2sv, glVertex3dv, glVertex3fv, glVertex3iv, glVertex3sv, glVertex4dv, glVertex4fv, glVertex4iv, glVertex4sv
数字の部分
数字の部分は、APIの引数の数を表します。例えば、glVertex2fは、xとyの2つ、glVertex3fなら、x,y,zの3つの引数を取ります。
d,f,i,s
文字の部分は引数の型を表します。それぞれ、dはGLdouble、fはGLfloat、iはGLint、sはGLshort型です。
v
vは、配列を引数に取ることを表します。

このような命名規則はOpenGLライブラリだけで、GLUやglutには適用されません。


OpenGLの座標系

座標系 なぜ、わざわざ座標系の話をするかというと、OpenGLの座標の取り方が、普通のコンピューターで図形を扱う時と異なるためです。
コンピューターの画面表示は、普通、x軸を画面の左から右に向かって、y軸を上から下にとります。3D処理をするときはさらにz軸を画面手前から奥に向かう方向で取ることが多いと思います。
しかし、OpenGLでは、図のように、y軸が画面下から上、z軸が画面奥から手前になるように取ります。数学で座標系を描くときによくやる取り方ですが、プログラムを書く人種にはちょっとなじみが薄い取り方かも知れません。


図形の描き方

OpenGLの基礎で、"State Machine"だと書きましたが、図形を描くのもState Machineの特色が出ています。
具体的に図形を描くには、下のようにglBegin()で、今から何を書くか指定し、次にglVertex〜を何度か呼んで頂点を指定して、glEnd()を呼ぶという手順を取ります。1つの図形を書くために3つも関数を呼ぶのはめんどくさいようにも思えますが、使ってみると複雑な図形でもプログラムをすっきりと書け、便利です。

OpenGLで三角形を描く

glBegin(GL_TRIANGLES);

glVertex2f( 0.0, 0.5);
glVertex2f(-0.5, -0.5);
glVertex2f( 0.5, -0.5);

glEnd();

OpenGLで描ける図形

OpenGLではglBegin()の引数を変えることによって、いろいろな図形を描くことができます。以下の表にまとめてみました。

glBegin()の引数と解説 説明の図
GL_LINES

独立した直線を描きます。

[図:GL_LINESの説明]
GL_LINE_STRIP

連続した直線を描きます。

[図:GL_LINE_STRIPの説明]
GL_LINE_LOOP

連続した直線を描きますが、最後に指定した点と最初に指定した点も直線で結ばれます。

[図:GL_LINE_LOOPの説明]
GL_TRIANGLES

独立した三角形を描きます。三角形の内側は塗り潰されます。

[図:GL_TRIANGLESの説明]
GL_TRIANGLE_STRIP

連続した三角形を描きます。

[図:GL_TRIANGLE_STRIPの説明]
GL_TRIANGLE_FAN

連続した三角形で扇形を描きます。

[図:GL_TRIANGLE_FANの説明]
GL_QUADS

独立した四角形を描きます。

[図:GL_QUADSの説明]
GL_QUAD_STRIP

連続した四角形を描きます。

[図:GL_QUAD_STRIPの説明]
GL_POLYGON

任意の数の頂点を持った多角形を描きます。ただし、GL_POLYGONは遅いので、GL_TRIANGLE_STRIPなどを使って多角形を描いた方がよいという話も聞いたことがあります。

図:GL_POLYGONの説明]

GL_POLYGONを使うときの注意

[図:GL_POLYGONでうまく描けない図形] GL_POLYGONGL_QUADSを使う場合、図のような内側にへこんだ図形は正しく描くことができません。このような図形を描くときは、三角形に分割して、GL_TRIANGLE_STRIPなどを使って描く必要があります。


glutでウインドウを表示する

sample01.cを見ながらglut APIの説明をします。今回のサンプルプログラムで使っているAPIは以下の7つです。

void glutInit(int* argc, char** argv)
glutライブラリの初期化をします。glutライブラリの他のAPIを呼ぶ前に必ずこれを1回呼んでください。引数のargcargvは、main()の引数として受け取ったものをそのまま渡してやります。
void glutInitDisplayMode(unsigned int mode)
画面の表示属性を設定します。今回は2D表示のみなのでGLUT_RGB(色情報をもつ)を設定します。3D表示をするときには、GLUT_DEPTH(奥行き情報を持つ)も設定したりします。
void glutInitWindowSize(int width, int height)
名前の通りです。ウインドウの大きさを設定します。
int glutCreateWindow(char *name)
ウインドウを作ります。nameには、ウインドウのタイトルを指定します。返値として、ウインドウの識別子が返ってきますが、このサンプルでは1つのウインドウしか使わないので無視しています。
void glutDisplayFunc(void (*func)(void))
画面を描き直すときに呼ぶ関数を登録します。glutでは、このような登録関数でイベント処理関数を登録すると、画面の更新やキーが押された、マウスが動いたといったイベントに応じて、イベント処理関数が呼ばれます。
void glutReshapeFunc(void (*func)(int width, int height))
ウインドウの大きさが変わったときに呼ばれるイベント処理関数を登録します。
void glutMainLoop()
イベント処理を開始します。これを呼ぶと、ウインドウが閉じられるまで戻ってきません。この関数の中で、必要なときに、画面更新関数(今回の場合はdisplay_func)などを呼んでくれます。

OpenGLによる二次元図形の描画

main()

main()関数の中は、glutでウインドウを表示するで解説した、glutの初期化処理やウインドウ作成の処理を行っています。

reshape_func()

次に、reshape_func()です。この関数は、ウインドウの大きさが変化した時に呼ばれて、引数にウインドウの幅と高さが渡されます。ここでは、glViewport()を呼ぶようにしています。

void glViewport(GLint x,GLint y, GLsizei w, GLsizei h)
OpenGLが表示に使う長方形領域を設定します。(x,y)が表示領域の左上の座標、(w,h)が表示領域の幅と高さになります。glViewport(0, 0, width/2, height/2)のようにすると、ウインドウの左上1/4に表示されるようになります。このAPIを呼ばないと正しく表示されないことがあるので注意しましょう。

display_func()

そうしたら、最後にdisplay_func()の解説をします。まず最初に、glClear()を呼んで画面を消去します。そこに、図形の描き方で説明したように、図形を書き込んでいきます。そして、最後にglFlush()を呼ぶと結果が画面に反映されます。

void glClear(GLbitfield mask)
画面を消去します。GL_COLOR_BUFFER_BITは、色情報を消去することを示します。
void glColor3f(GLfloat red, GLfloat green, GLfloat blue)
描画する色を指定します。(1.0,1.0,1.0)で白になります。
void glBegin(GLenum mode)
図形の描き始めを指示するAPI。引数には描きたい図形を指定します。必ず、glEnd()と対になっていなければなりません。
void glVertex2f(GLfloat x, GLfloat y)
図形の頂点を設定します。
void glEnd(void)
図形描画の終わりを示します。glBegin()と対で呼ばれなければなりません。
void glFlush(void)
このAPIを呼ぶと、画面が更新されます。

ご意見、ご感想は、花房 真広 <webmaster@hanabusa.net>まで。メールする前にtop pageの注意書を読んでください。