削除された内容 追加された内容
M X Window"s" Systemの誤記を修正。正しくはX Window System
編集の要約なし
7 行
ここまでで2Dのゲームプログラミングを見てきました.ここまででもある程度高度な数学が現れています.例えば,[[w:ベクトル]]や[[w:三角比]]はその例でどちらも[[高等学校数学]]で扱われる題材で、割合高度な数学といえます.残念ながら3Dプログラミングでは更に高度な数学が必要となります.
-->
3Dプログラミングでは4x4までの[[w:行列]]の演算が必要になります.2x2までの行列演算については[[高等学校数学C]]を参照してください.また、任意の階数の行列演算については[[線型代数学]]を参照してください.具体的には、逆行列を求める演算([[w:クラメールの公式]]、[[w:ガウス消去法]]など)までを学習しておくとよいでしょう。<!-- ほとんど全部だが ... 。 -->
 
また、ゲームによっては初等的な力学の法則を扱う場合があります.残念ながら3次元空間での一般的な力学運動は[[高等学校物理]]の範囲を超えます.このような内容を習得するには,[[古典力学]]を読む必要があります.
15 行
===3Dプログラミング===
 
[[w:3D]] (3 Dimension) プログラミングは3つの数値で表される座標を持つ物体を扱うプログラミング技法です.普通コンピュータで画面表示として用いられている[[w:ディスプレイ]]は、厚みのある事柄を表示することはできません.これは、ディスプレイの表示方法が2つの座標(縦と横)で表される表示方法であることによります.一方,計算機上のデータとしては,3つの数値を組として扱うことは,2つの数値を組として扱うことと比べて格別に難しいことではありません。そのため、ある物体が存在する位置を3次元の座標で表し,その座標を操作することで物体の3次元中での移動などを扱うことができます。この時,最終的に操作の結果を表示するには2次元のディスプレイを扱う必要があるため,3次元の座標を2次元の座標に変換する方法が必要になります.
 
3次元の座標から2次元の座標を引き出す方法として,射影行列([[w:線型代数学|線形代数]]などを参照)を利用する方法があげられます.射影行列<math>P_i</math>は,
:<math>
\sum _i P_i = 1
24 行
P_i ^2 = P_i
</math>
(和を取らない)を満たす行列のことです。ここでは、z軸方向を厚みの方向として取り,射影行列として,
:<math>
P_1 =
55 行
のx, y成分で表します.これはあらゆる3次元座標にただ1つの2次元座標を与える射影で,3次元座標から2次元座標を取り出す1つの方法ということになります.
 
ここまでで3次元座標から2次元座標を取り出す方法を述べました.ここからは、実際にこの方法をプログラムする方法を述べます.上の方法を扱うには、行列の計算と、ベクトルを扱う方法が必要です.実際にはこれらの方法はいろいろなライブラリで扱われており(例えば,[[w:en:GSL]]など),),実際のプログラミングではそれらを用いるとよいでしょう。もちろん自力で実装することもできます.
 
上で述べた通り,行列やベクトルを扱う演算はプログラムで扱うこともできますが,実際にはそれはあまり行われません.それはそのような計算は[[w:CPU]]にとって手間がかかることが多く,全てをCPUを使って計算しようとすると多くの時間がかかるからです。<!-- 実際には筆者の環境でmesaを使ってglxgearsを実行してみたところ、座標の計算というより扱うウィンドウの書き換えで時間を取っている。そのため、"行列の計算で"というのは語弊がある。 -->このような計算を扱うためには,[[w:グラフィックボード]]、[[w:ビデオカード]]と呼ばれる機器を使うことが推奨されます.これらは、3次元の計算をするために特化した演算装置(CPU(CPUに対して,[[w:GPU]]と呼ばれることがある)を持っており,CPUを使って計算を行うよりも速く演算を行うことができます.ただし、そのような機器がない環境でも全ての計算をCPUを使って行うことで3Dの描画を行うことは可能です.
 
ここまでで、3Dの計算を扱うために専用の機器を使えることを述べました.ここからは実際にそのような機器を使う方法について述べます.また、そのような機器がなくとも,同じプログラムを使ってCPUに計算をさせる方法があることについても述べます.
 
実際に何らかの機器を用意した時,その機器に実際に計算をさせるための手法が必要になります.この手法は環境によって少し異なっています.各社が発売している[[w:グラフィックボード]]の[[w:デバイスドライバ]]には,それらの機器を利用者のプログラムから利用するための一連の関数が用意されています.関数群には通常2つがあり、これらはそれぞれ[[w:DirectX]]、[[w:OpenGL]]と呼ばれます.[[w:Windows入門|Windows]]からは両方の関数群が使えることが普通です.一方,他の環境([[w:Mac OS X]]、[[w:Linux]]など)からはOpenGLしか使えません.これらの関数群は互いに互換性が無いので,実際に使用するときは注意が必要です.ここではOpenGLについて扱います.<!-- もちろんDirectXも扱った方がよいのだが ... 。 -->
 
ここで,グラフィックボードなどの機器が用意できないなどの理由で全ての計算をCPUに行わせる場合のことを述べます.この場合は基本的にグラフィックボードが提供する機能を1つ1つプログラムしていくことになります.実際には,このような場合には[[w:en:Mesa 3D]]などのライブラリを使うのが1つの手段です.Mesaは、OpenGLが提供する機能を実際にプログラムしたもので、1つ1つプログラムする手間が省けます.Mesaは[[w:オープンソース]]ライセンスで配布されているので自由に手に入れて使うとよいでしょう.<!-- Mesaの作者はすごい。 -->
 
ここまでで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を利用することを知らせる必要があります.
116 行
さて、ここまでで上の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:単位行列]]です。また、実際に使われるのはこれらの積であるので,値を変更するのは片方の行列だけでもあらゆる変換を指定することは可能です。
191 行
 
 
次に、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を利用しないときは
201 行
となります
 
次に、"遠くにあるものほど小さく見える"の場合について説明します。これを指定するためには,いくつかの変数が必要になります。まず、"物体を観察するもの"が (0,0,0) にあるとします。次に,遠くの物体が縮小される割合を指定します。これは、投影された後のx座標とy座標に対応して2つのパラメータが必要です。更に,見える方向がz方向で無い場合を扱うために2つのパラメータが必要となります。最後に,上で指定した角度の方向に実際に描画するz座標の範囲を指定します。これらを全て指定すると、描画される領域は角錐 ([[w:en:frustum]]) になります。
*図
実際にこの領域を指定するにはglFrustum関数を利用します。glFrustum関数は6つの引数を取りますが,それぞれの引数は
209 行
です。<!-- この行列がどのように上で解説した変換を行うかを次に説明します。 -->
 
[[en:Programming:OpenGL Programming]]
 
[[Category:情報技術]]