(Translated by https://www.hiragana.jp/)
OpenGL - Wikibooks コンテンツにスキップ

OpenGL

出典しゅってん: フリー教科書きょうかしょ『ウィキブックス(Wikibooks)』

3Dプログラミング

[編集へんしゅう]

3Dに必要ひつよう数学すうがく

[編集へんしゅう]

ここまでで2Dのゲームプログラミングをてきました。ここまででもある程度ていど高度こうど数学すうがくあらわれています。たとえば,w:ベクトルw:三角さんかくはそのれいでどちらも高等こうとう学校がっこう数学すうがくあつかわれる題材だいざいで、割合わりあい高度こうど数学すうがくといえます。残念ざんねんながら3Dプログラミングではさら高度こうど数学すうがく必要ひつようとなります。

3Dプログラミングでは4x4までのw:行列ぎょうれつ演算えんざん必要ひつようになります。2x2までの行列ぎょうれつ演算えんざんについては高等こうとう学校がっこう数学すうがくC参照さんしょうしてください。また、任意にんい階数かいすう行列ぎょうれつ演算えんざんについては線型せんけい代数だいすうがく参照さんしょうしてください。具体ぐたいてきには、ぎゃく行列ぎょうれつもとめる演算えんざんw:クラメールの公式こうしきw:ガウスの消去しょうきょほうなど)までを学習がくしゅうしておくとよいでしょう。

また、ゲームによっては初等しょとうてき力学りきがく法則ほうそくあつか場合ばあいがあります。残念ざんねんながら3次元じげん空間くうかんでの一般いっぱんてき力学りきがく運動うんどう高等こうとう学校がっこう物理ぶつり範囲はんいえます。このような内容ないよう習得しゅうとくするには,古典こてん力学りきがく必要ひつようがあります。

いずれにしても、3Dプログラミングに必要ひつよう数学すうがくw:理系りけい大学だいがく1, 2ねん程度ていどなら内容ないようです。

3Dプログラミング

[編集へんしゅう]

w:3D (3 Dimension) プログラミングは3つの数値すうちあらわされる座標ざひょう物体ぶったいあつかうプログラミング技法ぎほうです。普通ふつうコンピュータで画面がめん表示ひょうじとしてもちいられているw:ディスプレイは、あつみのある事柄ことがら表示ひょうじすることはできません。これは、ディスプレイの表示ひょうじ方法ほうほうが2つの座標ざひょうたてよこ)であらわされる表示ひょうじ方法ほうほうであることによります。一方いっぽう計算けいさん機上きじょうのデータとしては,3つの数値すうちくみとしてあつかうことは,2つの数値すうちくみとしてあつかうこととくらべて格別かくべつむずかしいことではありません。そのため、ある物体ぶったい存在そんざいする位置いちを3次元じげん座標ざひょうあらわし,その座標ざひょう操作そうさすることで物体ぶったいの3次元じげんちゅうでの移動いどうなどをあつかうことができます。このとき最終さいしゅうてき操作そうさ結果けっか表示ひょうじするには2次元じげんのディスプレイをあつか必要ひつようがあるため,3次元じげん座標ざひょうを2次元じげん座標ざひょう変換へんかんする方法ほうほう必要ひつようになります。

3次元じげん座標ざひょうから2次元じげん座標ざひょう方法ほうほうとして,射影しゃえい行列ぎょうれつ線形せんけい代数だいすうなどを参照さんしょう)を利用りようする方法ほうほうがあげられます。射影しゃえい行列ぎょうれつは,

らない)をたす行列ぎょうれつのことです。ここでは、zじく方向ほうこうあつみの方向ほうこうとしてり,射影しゃえい行列ぎょうれつとして,

ります。この2つの行列ぎょうれつたします。ここで、あるてんの3次元じげん座標ざひょう

としたとき,そのてんの2次元じげん座標ざひょう

のx, y成分せいぶんあらわします。これはあらゆる3次元じげん座標ざひょうにただ1つの2次元じげん座標ざひょうあたえる射影しゃえいで,3次元じげん座標ざひょうから2次元じげん座標ざひょうす1つの方法ほうほうということになります。

ここまでで3次元じげん座標ざひょうから2次元じげん座標ざひょう方法ほうほうべました。ここからは、実際じっさいにこの方法ほうほうをプログラムする方法ほうほうべます。うえ方法ほうほうあつかうには、行列ぎょうれつ計算けいさんと、ベクトルをあつか方法ほうほう必要ひつようです。実際じっさいにはこれらの方法ほうほうはいろいろなライブラリであつかわれており(たとえば,w:en:GSL(GNU Scientific Library)など),実際じっさいのプログラミングではそれらをもちいるとよいでしょう。もちろん自力じりき実装じっそうすることもできます。

うえべたとおり,行列ぎょうれつやベクトルをあつか演算えんざんはプログラムであつかうこともできますが,実際じっさいにはそれはあまりおこなわれません。それはそのような計算けいさんw:CPUにとって手間てまがかかることがおおく,すべてをCPUを使つかって計算けいさんしようとするとおおくの時間じかんがかかるからです。このような計算けいさんあつかうためには,w:グラフィックボードw:ビデオカードばれる機器きき使つかうことが推奨すいしょうされます。これらは、3次元じげん計算けいさんをするためにとくした演算えんざん装置そうち(CPUにたいして,w:GPUばれることがある)をっており,CPUを使つかって計算けいさんおこなうよりもはや演算えんざんおこなうことができます。ただし、そのような機器ききがない環境かんきょうでもすべての計算けいさんをCPUを使つかっておこなうことで3Dの描画びょうがおこなうことは可能かのうです。

ここまでで、3Dの計算けいさんあつかうために専用せんよう機器きき使つかえることをべました。ここからは実際じっさいにそのような機器きき使つか方法ほうほうについてべます。また、そのような機器ききがなくとも,おなじプログラムを使つかってCPUに計算けいさんをさせる方法ほうほうがあることについてもべます。

実際じっさいなんらかの機器きき用意よういしたとき,その機器きき実際じっさい計算けいさんをさせるための手法しゅほう必要ひつようになります。この手法しゅほう環境かんきょうによってすこことなっています。各社かくしゃ発売はつばいしているw:グラフィックボードw:デバイスドライバには,それらの機器きき利用りようしゃのプログラムから利用りようするための一連いちれん関数かんすう用意よういされています。関数かんすうぐんには通常つうじょう2つがあり、これらはそれぞれw:DirectXw:OpenGLばれます。Windowsからは両方りょうほう関数かんすうぐん使つかえることが普通ふつうです。一方いっぽう環境かんきょうw:Mac OS Xw:Linuxなど)からはOpenGLしか使つかえません。これらの関数かんすうぐんたがいに互換ごかんせいいので,実際じっさい使用しようするときは注意ちゅうい必要ひつようです。ここではOpenGLについてあつかいます。

ここで,グラフィックボードなどの機器きき用意よういできないなどの理由りゆうすべての計算けいさんをCPUにおこなわせる場合ばあいのことをべます。この場合ばあい基本きほんてきにグラフィックボードが提供ていきょうする機能きのうを1つ1つプログラムしていくことになります。実際じっさいには,このような場合ばあいにはw:en:Mesa 3Dなどのライブラリを使つかうのが1つの手段しゅだんです。Mesaは、OpenGLが提供ていきょうする機能きのう実際じっさいにプログラムしたもので、1つ1つプログラムする手間てまはぶけます。Mesaはw:オープンソースライセンスで配布はいふされているので自由じゆうれて使つかうとよいでしょう。

ここまでで3Dの計算けいさんおこな方法ほうほうについてべました。ここでは実際じっさいにOpenGLのプログラムをあつかいます。OpenGLのチュートリアルはWebじょう公開こうかいされているので,紹介しょうかいします。(OpenGL Redbook http://fly.srk.fer.hr/~unreal/theredbook/ ) また、OpenGLの詳細しょうさい規定きていは、http://www.opengl.org/documentation/specs/入手にゅうしゅできます。

OpenGLを利用りようして計算けいさんおこなうのですが、OpenGLがおこなうのはあくまで計算けいさんであり,画面がめんへの描画びょうがではいことに注意ちゅうい必要ひつようです。画面がめんへの描画びょうがはOpenGLでの計算けいさん結果けっかしたがって描画びょうがあつかうプログラムがおこないます。Linuxでは描画びょうがw:X Window Systemおこない,Mac OS Xでは、w:quartzおこないます。そのため、結果けっか描画びょうがおこなうためには,描画びょうがおこなうプログラムに,OpenGLを利用りようすることをらせる必要ひつようがあります。

残念ざんねんことにこの作業さぎょうおこな方法ほうほうはウィンドウシステムによってことなっています。Xの場合ばあいにはglX関数かんすう使つかい,Xに指示しじしますが、この方法ほうほうのプラットフォームでは使つかえません。さいわいにもこのような作業さぎょう様々さまざまなプラットフォームで使つか方法ほうほうとして,w:GLUTw:SDLなどを利用りようすることができます。ここでは、SDLを利用りようする方法ほうほうについてべます。

GLUTは本来ほんらいGLの利用りよう簡単かんたんにするためにつくられました。一方いっぽう,SDLは本来ほんらいゲームプログラミングをおこなうことを目的もくてきとしてつくられたライブラリです。しかし、いずれにしろ3DプログラミングをおこなうためにはOpenGLの利用りよう必須ひっすなので,SDLもGLUTにちか機能きのうっています。どちらもWindows, Mac OS X, LinuxじょうでOpenGLの動作どうさはじめることができます。

SDLでOpenGLを利用りようするときには

#include <SDL.h>
#include <GL/gl.h>
int main()
{
    if (SDL_SetVideoMode(200, 200, 0, SDL_OPENGL) == NULL)
        return 10;
     /*  OpenGLの処理しょり */
     SDL_GL_SwapBuffers();
    return 0;
}

とします。ここではこのプログラムについてじゅん説明せつめいしていきます。まず、OpenGLを使つかわなくとも、SDLを利用りようする場合ばあいでも、1, 3, 4, 5, 6, 9, 10ぎょう必要ひつようとなります。ただし,4ぎょうは、

    SDL_Surface *surf;
    if (surf = SDL_SetVideoMode(200, 200, 0, 0))

などとえる必要ひつようがあります。

  • 1ぎょうは,SDLを利用りようするさい必要ひつようとなるヘッダファイルです。これはつね必要ひつようになります。
  • 2ぎょうはOpenGLの関数かんすう利用りようするとき必要ひつようとなるヘッダです。この部分ぶぶんたとえ,GLUTを利用りようするとしても,わりはありません。それは、SDLであるにしろ,GLUTであるにしろどちらもウィンドウシステムからOpenGLの領域りょういきることにわりはないからです。そのため、利用りようするヘッダも、2つのライブラリで共通きょうつうのものを利用りようします。
  • 3,4, 9, 10ぎょうはほとんどすべてのCプログラムで必要ひつようになります。
  • 5ぎょうでOpenGLの領域りょういきをウィンドウシステムからっています。SDL_SetVideoModeは本来ほんらいのSDLではえられたプログラムの5ぎょうのように描画びょうがおこなうSDL_Surfaceという構造こうぞうたいかえします。しかし、4つめの引数ひきすうにSDL_OPENGLのw:フラグったときには,OpenGLの領域りょういき初期しょきするように動作どうさ変化へんかします。かりにこの動作どうさ失敗しっぱいした場合ばあいには,この関数かんすうはNULLをかえすので,その場合ばあいにはここでプログラムを終了しゅうりょうするのが普通ふつうです。
  • 7ぎょう以降いこうでOpenGLの関数かんすうきます。ここについてはあとべます。
  • 8ぎょうではSDL_GL_SwapBuffersという関数かんすう使つかっています。この関数かんすうはOpenGLの関数かんすう描画びょうがした図形ずけいを、実際じっさいにウィンドウに描画びょうがする関数かんすうです。この方法ほうほうw:ダブルバッファ簡単かんたん実現じつげんしてくれます。GLで描画びょうがされた内容ないよう実際じっさい表示ひょうじされるのは,この関数かんすう以降いこうです。また、実際じっさい描画びょうがおこなってもこのままではすぐにプログラムが終了しゅうりょうしてしまうので,描画びょうが結果けっかるためには,whileループかsleepなどの関数かんすう利用りようして,プログラムの実行じっこうつづける必要ひつようがあります。実際じっさいにはSDLはSDL_Delayというプログラムの実行じっこう一時いちじてきおくらせる関数かんすうっているので,この関数かんすう使つかうのもよいでしょう。

ここからは、実際じっさいにOpenGLの関数かんすういていきます。ここでかれるプログラムはうえのプログラムの7ぎょう以降いこうかれるものです。

    glBegin(GL_LINE_LOOP);
    glVertex3d(0,0,0);
    glVertex3d(0,1,0);
    glVertex3d(1,0,0);
    glEnd();

このプログラム(tri.cとする)をコンパイルするには,いくつかのコンパイラオプションが必要ひつようです。コンパイラがw:GCCなら、

$gcc -Wall tri.c -L libGLのある場所ばしょ -I GL/gl.hのある場所ばしょ -lGL $(sdl-config --cflags --libs)

となります。実際じっさいにGLの関数かんすうかれている場所ばしょ環境かんきょうによります。X+MesaではXがかれているディレクトリにあることが普通ふつうですが,グラフィックボードのドライバを利用りようするなら,w:メーカー指定していしたディレクトリを使つか必要ひつようがあります。また、うえれいでは必要ひつようないですが,-lGLUをつける場合ばあいもあります。これはglu.hで定義ていぎされた関数かんすう利用りようする場合ばあい使つかいます。glu.hの関数かんすう実際じっさいにはgl.hの関数かんすうをいくつかわせた関数かんすうですが,よくもちいられるわせなので、gl.hの関数かんすうとともに配布はいふされます。

このプログラムを実行じっこうすると,くろ背景はいけいなかしろい3角形かくがたえがかれるはずです。

うえのプログラムの結果けっか説明せつめいするにはいくつかの事柄ことがら説明せつめいする必要ひつようがあります。まず、うえのプログラムないで,

glBegin(), glEnd()

という関数かんすう使つかわれています。この関数かんすうはそのなか指定していされた事柄ことがら(おも頂点ちょうてんかんする事柄ことがら)を記録きろくさせます。記録きろくできる事柄ことがら頂点ちょうてん位置いちいろなどがあります。頂点ちょうてん位置いち指定していするには

glVertex3f()

使つかうことができます。ここでこの関数かんすうめいはOpenGLに特徴とくちょうてき事柄ことがらをいくつかふくんでいます。最後さいごの3fがそれでこれはそれぞれこの関数かんすうが"3つ"の引数ひきすうることと、そのかたが"GLfloat"であることです。ここでGLfloatはほとんどの場合ばあいfloatがたのtypedefになっています。これ以降いこうにもこのたね関数かんすうめいなんてきます。glVertex3fは、3つの引数ひきすうによってそれぞれ3次元じげん座標ざひょう指定していします。

さて、ここまででうえのGLプログラムの1-5ぎょうが、3つの座標ざひょう指定していしたことがわかります。実際じっさいにそれらの座標ざひょうをどう使つかうかについてはglBegin()の引数ひきすう使つかわれます。ここではGL_LINE_LOOPを使つかったので,指定していされた座標ざひょう指定していされたじゅん直線ちょくせんでつながれます。

ここまでで、うえのプログラムちゅう座標ざひょう (0,0,0),(0,1,0),(0,0,1) が指定していされ,これらが直線ちょくせんでつながれることがわかりました。これは3次元じげんちゅうで3角形かくがたえがくことがわかります。つぎ問題もんだいは,この三角形さんかっけいがどのようにディスプレイに投影とうえいされるかです。

OpenGLは3次元じげんちゅう指定していされた座標ざひょうの2次元じげんちゅうでの位置いちさだめるために2つの行列ぎょうれつ利用りようします。ここで、OpenGLでは行列ぎょうれつを"あつかう"場所ばしょは1つしか用意よういしなくてもいいことがさだめられています。もちろん、保存ほぞんしておく場所ばしょ複数ふくすうあるのですが,これらの変更へんこうするのに使つか領域りょういきは1つです。そのため、これらの行列ぎょうれつ使つかけるには,これらを所定しょてい場所ばしょ必要ひつようがあります。ここで行列ぎょうれつ指定していするには,glMatrixMode()関数かんすう使つかいます。この関数かんすうは1つの引数ひきすうり、その行列ぎょうれつ指定していします。2次元じげんちゅうでの位置いち指定していするのに使つか行列ぎょうれつはそれぞれGL_MODELVIEW, GL_PEROJECTIONで指定していされます。これらの行列ぎょうれつ初期しょきは4x4のw:単位たんい行列ぎょうれつです。また、実際じっさい使つかわれるのはこれらのせきであるので,変更へんこうするのは片方かたがた行列ぎょうれつだけでもあらゆる変換へんかん指定していすることは可能かのうです。

ここで2つの行列ぎょうれつのそれぞれについてその性質せいしつべます。GL_MODELVIEW行列ぎょうれつはそれぞれの頂点ちょうてん座標ざひょう変更へんこうするのに利用りようします。実際じっさいには大抵たいてい場合ばあい、この行列ぎょうれつ

glRotatef(), glScalef(), glTranslatef()

の3つの関数かんすうから利用りようされます。 これらの関数かんすうじゅんに,座標ざひょうを"回転かいてん", "拡大かくだい縮小しゅくしょう", "平行へいこう移動いどう"します。これらの関数かんすうはそれぞれ対応たいおうする変換へんかんおこな行列ぎょうれつ生成せいせいし、選択せんたくされている行列ぎょうれつ変換へんかんします。ここではそれらの行列ぎょうれつ詳細しょうさいについて解説かいせつします。対応たいおうする行列ぎょうれつについてはそれぞれのmanを参照さんしょうしてください。(OpenGLのspecification http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/ )

translateの生成せいせいする行列ぎょうれつは、

あたえられます。この行列ぎょうれつは、もと頂点ちょうてんの3次元じげん座標ざひょうあらわされるときのどうつぎ座標ざひょうを、変換へんかんしますが、これはまさに平行へいこう移動いどうによってこされる座標ざひょう変換へんかん対応たいおうしています。

scaleの生成せいせいする行列ぎょうれつは、

です。この変換へんかんは3次元じげん座標ざひょうを、変換へんかんします。これはx,y,zのによってそれぞれの座標ざひょう拡大かくだい縮小しゅくしょうする変換へんかん対応たいおうします。

最後さいごに、rotateでられる行列ぎょうれつ紹介しょうかいします。

この変換へんかん導出どうしゅつすこ厄介やっかいです。まず、原点げんてんからはじまり、回転かいてん方向ほうこういている単位たんいベクトルをとし、ある頂点ちょうてん座標ざひょうあらわすベクトルをとします。このとき、この回転かいてん変化へんかするのは、のうち、平行へいこうでない成分せいぶんのみです。

平行へいこう成分せいぶんは、

あらわされるので、実際じっさい回転かいてんによって変化へんかする成分せいぶんは、からうえぶんのぞいたベクトルです。このベクトルをびます。このベクトルは回転かいてんによって変化へんかしますが、これをあらわすには、両方りょうほう直交ちょっこうするベクトルが必要ひつようです。このベクトルを、

ります。このとき、回転かいてんする角度かくどとすると、のベクトルは、けます。

結局けっきょくられるベクトルは、

となります。ここからは、この結果けっかうえしき一致いっちすることをしめすため、このしき整理せいりしていきます。まず、について、3x3行列ぎょうれつ

定義ていぎすると、ちます。また、について、3x3行列ぎょうれつ

定義ていぎすると、ちます。このことから結果けっかしきについて、

られますが、これを整理せいりするともとめていた行列ぎょうれつxあらわれます。


つぎに、GL_PROJECTION行列ぎょうれつについてべます。OpenGLでは、頂点ちょうてん座標ざひょうについてこれらの行列ぎょうれつをかけたのち (-1, -1, -1), (1,1,1) で指定していされる立方体りっぽうたいないにある図形ずけいえがきます。このため、たとえば (0,0,10) にある図形ずけい一般いっぱんにはえがかれません。しかし、図形ずけいを3次元じげんちゅうえがくときの事情じじょうで、これらの位置いち自由じゆう指定していできないと不便ふべんです。GL_PROJECTION行列ぎょうれつは"描画びょうがされる範囲はんいひろげる"目的もくてき利用りようされます。また、この行列ぎょうれつは、"とおくにあるものほどちいさくえる"という状況じょうきょうあつかうためにも利用りようされます。

まず、"描画びょうがされる範囲はんいひろげる"場合ばあいについて行列ぎょうれつ指定してい仕方しかた説明せつめいします。実際じっさいには範囲はんいひろげているのではく,"(-1,-1,-1)(1,1,1) ないはいるように、とおくにあるものをちかくにってきている"のがただしいのですが、どちらにしろ結果けっかおなじです。これを指定していするにはglOrtho()関数かんすう利用りようします。glOrtho関数かんすうは6つの引数ひきすうり,それぞれ描画びょうがする立方体りっぽうたい一般いっぱんには直方体ちょくほうたい)を指定していする座標ざひょうります。引数ひきすうじゅん

glOrtho(left, right, bottom, top, near, far)

ばれ,描画びょうがされる直方体ちょくほうたいは(left, bottom, near)(right, top, far)で指定していされます。このとき、glOrthoを利用りようしないときは

glOrtho(-1, 1, -1, 1, -1, 1)

指定していされたときとおな結果けっかになることがわかりますが、実際じっさいにはこの指定していは4x4の単位たんい行列ぎょうれつかえすので指定してい省略しょうりゃくしたときと結果けっかおなじになります。対応たいおうする行列ぎょうれつ

  • 行列ぎょうれつ

となります

つぎに、"とおくにあるものほどちいさくえる"の場合ばあいについて説明せつめいします。これを指定していするためには,いくつかの変数へんすう必要ひつようになります。まず、"物体ぶったい観察かんさつするもの"が (0,0,0) にあるとします。つぎに,とおくの物体ぶったい縮小しゅくしょうされる割合わりあい指定していします。これは、投影とうえいされたのちのx座標ざひょうとy座標ざひょう対応たいおうして2つのパラメータが必要ひつようです。さらに,える方向ほうこうがz方向ほうこう場合ばあいあつかうために2つのパラメータが必要ひつようとなります。最後さいごに,うえ指定していした角度かくど方向ほうこう実際じっさい描画びょうがするz座標ざひょう範囲はんい指定していします。これらをすべ指定していすると、描画びょうがされる領域りょういき角錐かくすい (w:en:frustum) になります。

実際じっさいにこの領域りょういき指定していするにはglFrustum関数かんすう利用りようします。glFrustum関数かんすうは6つの引数ひきすうりますが,それぞれの引数ひきすう

glFrustum(left, right, top, bottom, near, far)

あたえられる名前なまえをもっており、縮小しゅくしょうされる割合わりあいさだめる四角形しかっけいがl, r, t, b、四角形しかっけい位置いちがn、描画びょうがされる範囲はんいがfでさだめられます。glFrustumであたえられる行列ぎょうれつ

  • 行列ぎょうれつ

です。