元ネタ:bd-interactively All about OpenGL ES 2.x – (part 1/3)
> part 2/3
原文とあわせてお読みください。和訳の正確性と内容の信憑性については話半分ということで。
追記:
この記事を書いたあとで元ネタサイトのコメント欄で、和訳の要約を自分のサイトで公開していい?と質問したところ。
Sure I liked it.とお返事をいただきました。感謝ですね。
At a glance
OpenGL とは
- さまざまなプラットフォーム、OSで使用できるグラフィックライブラリ
- windows, mac, Linux
- c, c++, Java, Perl, Javascript etc.
- OpenGLES2.0 はPlaystation, Android, Nokia などに使われている。
著者は2004年の OpenGL2.0 のリリースで感激したらしい。 DirectX は嫌い。
3D world
3次元空間の視覚化とは視覚の再現である。perpectives*、消失点、歪み、深度、焦点、field of view。field of view、単眼/複眼、凹型/凸型レンズなどを理解すると良い。
* perspectives の間違い?
3Dとは3つの次元をもつから3Dである。うわ、何をする、落ち着け。ここで重要なのは「2Dに対して+1の次元を持つ」ということ。
例えば平面上で物体を45度回転するのは簡単。しかし3次元空間ではX軸回転してもいいし、Y軸でも斜めでも良い。当然、軸によって回転後の状態は異なることになる。
つまり次元が「+1」されたということによってかなり複雑になるってこと。
それから「時間」という概念を加えて考えると、3Dは4Dにもなりうる。
OpenGL into the 3D world
OpenGL がどのように動いているか、ということを説明する。
まずは港にあるクレーンを思い浮かべよう(元ネタサイトの写真をみるべし)。港にはコンテナがたくさんあり、なかには crate(木箱?)が入っている。
- 港全体が OpenGL
- コンテナが OpenGL オブジェクト (= Textures, Shaders, Meshes etc)
- コンテナ内の crate は OpenGL を使って僕らが作ったもの (= our instance)
- ポートクレーンは僕らが使える OpenGL の API
僕らが OpenGL のメソッドを呼び出すのはクレーンに指令をあたえるようなもの。
- クレーンがコンテナをつかみ、
- 持ち上げ、
- そのままコンテナの中でいろんな処理をおこなう。
- 処理が終わったらコンテナは港のどこかにまた下ろされる。
僕らは港には直接アクセスすることはできないし、コンテナの中身を変えることもできない。できるのはクレーンに指令を出すことだけ。
不便なだけに見えるが、そんなことは無い。クレーンは強力で1秒間に何千何万回の指令をこなすことができる。また、 State Machine pattern で設計されているので僕らは余計な情報をもっておく必要がない(コンテナとして預けている)。IDを1つ持っておけば(クレーンの例で言うとコンテナを区別できれば)良いので楽チンである。
How OpenGL works
コンピューターには CPU と GPU がある。CPUはコンピューターや機器の計算処理装置であり、GPU (Graphics Processing Unit)はコンピュータや機器のグラフィックカードである。画像処理は大変なので、GPU がこれを担当していて、おかげで CPU の負担は軽減されている。
CPUに比べて GPU は浮動小数点の扱いにたけている。グラフィックカードの良し悪しで3Dゲームの動きが変わるのはこのため。
といってもOpenGL が完全に GPU の上に乗っかっているわけではなく、モノとしてはハードとは別物。OpenGL が使えるかどうかはそのグラフィックカードが OpenGL に対応しているかによる。
OpenGL’s Logic
プロの3Dソフトウェアは OpenGL でもって超スーパーウルトラ複雑奇妙奇天烈である。その OpenGL のロジックが処理できるのはいくつかのこと。
- Primitives
- バッファ
- ラスタライズ
そう。ではこれらについて1つ1つみていこう。ちなみに2DだとしてもZ深度をゼロとした3Dで扱うことが可能。
・Primitives(和訳:原始的な、基本の)
プリミティブとは基本の形のこと。以下の3つをつかうことができる。
- 3D Point:3次元上の1点 (x, y, z)
→ およびパーティクルに使用される。 - 3D Line:1本の線(3D Point x2個で構成される)
→ 3D Vector に利用される。 - 3D Triangle:1個の三角形(3D Point x3個で構成される)
→ メッシュ(≒立体の物体)の1面として利用される。
・バッファ
簡単に言うと「一時的で最適なデータ倉庫」。OpenGL は3種のバッファをもつ。
- Frame Buffer
- Render Buffer
- Buffer Object
レンダリングの時に、僕らは最終的なイメージをディスプレイに直接送ることもできるし、Frame Buffer に送ることもできる。では Frame Buffer はただの保管庫かというとそうではない。
最終的なイメージは1つのデータから作られるのではないことがほとんど。3Dオブジェクトならオブジェクトの深度もあるし、交差もしているかもしれない。Frame Buffer は画像の集合のように、頂点ごとのデータを保持している。
Render Buffer は一時的な1イメージのデータ倉庫。Frame Buffer は Render Buffer の集合である。Render Buffer にはいくつかの種類がある。
- Color Render Buffer:最終的な「色」を表すイメージ
- Depth Render Buffer:最終的なZ方向の深度(奥行き)の情報
- Stencil Render Buffer:可視部分を制限するオブジェクト(マスクのように)。黒と白のイメージで構成される
Buffer Object は OpenGL がサーバーサイドと呼ぶ保管庫である*。他のバッファと異なり、データとして保持される期間が長い。3D オブジェクトの最適化された情報をもち、その種類は Structures(構造)と Indices(複:index)に分けられる。
(* 原文:Buffer Objects is a storage which OpenGL calls “server-side”)
Structures は頂点配列やテクスチャ座標配列などの3Dオブジェクトを描画するための情報のリスト。Indices は例えば3Dオブジェクトのある面がどうやって構成されているかを表す。
たとえば3次元空間の立方体について考える(元ネタサイトの画像をみるべし)。1つ1つの面は四角形だが OpenGL は扱えないので三角形にして、全部で12の三角形で描くことになる。
<以下意訳あり>
ここで、
- 1つめの面は頂点Aと頂点Bと頂点Cをつないだ面
- 2つめの面は頂点Bと頂点Cと頂点Dをつないだ面
- 3つめの面は頂点Dと頂点Eと頂点Fをつないだ面
- ・・・・・
ではどうするかというと、頂点は頂点だけの情報リストとして持ち、面はその点情報のどれを使うかということだけを記録する。
vertex0 = new Vertex(20,20); vertex1 = new Vertex(40,20); vertex2 = new Vertex(40,40); vertex3 = new Vertex(20,40); vtxList = [vertex1, vertex2, vertex3, vertex4]; tri0 = new Triangle(0,1,2); tri1 = new Triangle(1,2,3);以上のコードで tri0 は vtxList 内の 0, 1, 2にある要素、つまりvertex0, vertex1, vertex2 で構成されることを表すことができる。ここでは三角形が2つだけなのでかえってデータ量は多くなっているが、これが膨大な量になったときは言わずもがな。
OpenGL の実際では以下のようになる。
vtxList = [vertex1, vertex2, vertex3, vertex4]; triList = [0,1,2,1,2,3];この配列のデータが3で区切られて利用される。つまり1つめの面は vtxList 内の0, 1, 2の頂点で構成され、2つめの面はvtxList 内の1, 2, 3の頂点で構成される、となる。
ここでバッファの話に戻ると、vtxList が Structures、triList が Indeces となる。
・ラスタライズ
ラスタライズとは3次元のすべての情報(頂点・座標・数学など)を2次元へ変換する処理である。スクリーンは2次元だからね。
しかしこれをやるかやらないかは機器メーカーの勝手。OpenGL を管理している Khronos group は OpenGL のためにルール(EGL という API)を提供しているが、メーカーはこれを改変することができる。
よって OpenGL の API で直接に Frame Buffer に書きこむのではなく、各メーカーが決めているルールに従って描画処理を書く必要がある。このルール(= API) はメーカーから提供される。
OpenGL’s pipelines
ここで2つのパイプライン
- Programmable pipeline:プログラム可能なパイプライン
- fixed pipeline:固定パイプライン
Programmable pipeline では開発者はカメラ・ライト・材質・効果などすべてのことを設定しなければならない。そしてこの設定はかの有名なシェーダーで行うことができる。Programmable pipeline はシェーダーだと捉えられることが多い。
Programmable pipeline はコードとしては断片的だが GPU の複雑な計算に直接につながっている。複雑ってどういうことかというと、あるピクセルの色を決めようとしたら、テクスチャの情報・ライトの情報(色、角度、位置、強さetc)・カメラの情報(色、角度、位置etc)、・・・といったように多数の情報が必要になる。でもってこれを設定しなければならん、と。
fixed pipeline はこれらのすべての情報をまとめて僕らに提供する。
シェーダーの設定にはC言語によく似た言語、OpenGL Shader Language (GLSL) を使う。Open GL ES は機能制限があり、OpenGL ES Shader Language (GLSL ES or ESSL) という言語になる。構文などは同じで使える範囲が異なるだけ。
シェーダーは頂点シェーダー(VS, or VSH) とフラグメントシェーダー(FSH) の2つではたらく。
頂点シェーダーはそれぞれの頂点で実行される小さなプログラム。頂点の最終的な位置を決める処理を行う。立方体ならその頂点の数だけ、つまり8回処理が行われる。
頂点自体の空間上の位置に加えて視点(カメラ)の情報も決定する必要がある。フラグメントシェーダーにいくつかの情報を渡さなければいけないが、僕らは頂点シェーダーを通さなければフラグメントシェーダーにアクセスすることができない。
立方体を眺めてみよう。立方体には8つの角と6つの面があるが、頑張っても同時に見ることが出来るのは7つの頂点とそれから構成された3つの面だけ。この「どのように見えるか」を処理するのがフラグメントシェーダーの仕事。テクスチャ・カメラ・ライト・重なりなどの要素をすべて考慮してスクリーン上のピクセルの色を決定する。
頂点シェーダーとフラグメントシェーダーが一緒に(1体1対応で)動いているということを知っておくこと。 結局のところ、 OpenGL のプログラムは頂点シェーダーとフラグメントシェーダーのコンパイルされた1対のものであって、それ以上のものではない。
Conclusion(まとめ)
- OpenGL のロジック部分は3つの Primitives から構成されている。
- fixed pipeline は重いしでかい。機能が固定されている。Programmable pipeline は簡単で速くて、いろいろ設定もできる。
- Programmable pipeline はシェーダーと同義語。頂点シェーダーとフラグメントシェーダーの2つで構成され、最終的にはプログラムの中にコンパイルされる。
と、このように理解するのは簡単だが、学ぶとなると、、、うーん。
次の2パートで実際のコーディングなどを見ていくが、もう1つの OpenGL のコンセプトを紹介しよう。
OpenGL’s Error API
港の例で紹介したように、OpenGL の内部に直接アクセスすることはできない。もしその内部でエラーが起こったらアプリケーションは止まってしまう。
この内部エラーを知るために、OpenGL から API が提供されている。2つの種類があって、1つはエラーがあるかを返すもの。もう1つはエラー内容を知るためのもの。
「チェック → エラー内容チェック」の流れを必要な箇所(バッファやシェーダの設定時など)できちんと行いましょう。
以上。
この著者さんは良い意味で OpenGL love なギークだなあという印象。でもって一般に面倒だと言われる Programmable pipelineを強烈プッシュ。
英語を流し読みする感覚がぼちぼち戻って来ましたが、次のパートは超膨大なのでどうしようかと考え中です。
"storage" の良い和訳ないですかねえ。保管庫にしてしまいましたが。
0 件のコメント:
コメントを投稿