月別アーカイブ: 2015年11月

OpenGL ES 2.0で波紋を作る#7 板ポリゴンに動きをつける

 

最終章です。板ポリゴンへの動きのつけ方を解説します。

ポイント

 ・3D座標のz軸

波紋

板ポリゴンでは、x軸とy軸を利用して2Dポリゴンを画面に描画しました。

この板ポリゴンのz軸に対して高さをつけると、板ポリゴンが3Dポリゴンに変わります。

 

今回は、このz軸の算出がポイントです。

z軸には、中心座標から距離と時間に応じて高低差をつけます。高低差はサイン波を利用します。サイン波により波の広がりが表現できます。

 

では、板ポリゴンに波の広がりを付けてみましょう。

波紋作成

今回は、以下のファイルを修正します。

 ・Shader.vsh

 ・Shader.fsh

 ・GameViewController.m

 

変更箇所について解説します。

変更箇所は、背景を反転させています。

Shader.vsh

 

定数は、WAVE_HEIGHT:波の高さ、WAVE_WIDTH:波の幅、WAVE_SPEED:波の速度、PI:円周率を設定します。

 

mainメソッドには、以下を追加します。

 ・波の広がりであるz軸の算出

 ・フラグメントシェーダに連携するためのカラーの設定

 

波の広がりの算出は、以下のとおりです。

  波の広がり(z軸の高さ) = 波の高さ ✕ sin(半径 ー 時間)

 

波の高さは、座標0から離れるに従ってなくなるようにします。係数を1.0にすると端の波がなくなります。今回は、波紋に見せるため1.3の係数を掛けます。

半径は、p.xy におけるベクトル空間の距離を算出します。

時間は、drow_count と定数を利用して速度を調整します。

サイン波の算出は、定数を利用して波の幅を調整します。

 

フラグメントシェーダには、z軸の高さを連携します。

Shader.fsh

 

カラーは、頂点シェーダから連携されたz軸の高さを利用します。

 

z軸の範囲は、頂点シェーダの定数 WAVE_HEIGHT になります。ここでは、 -0.05〜0.05の間で設定されます。

 

カラーは0.0〜1.0で設定されるため、-0.05〜0.05が0.0〜1.0になるように変換処理を追加します。

また、水の色としてRGBカラーの赤:0.5、緑:0.9、青:0.9を設定します。この時、波の低い箇所は暗く、高い箇所は明るくなるように gl_FragColor を調整します。

GameViewController.m

 

頂点シェーダで波の広がりを算出するための変数 count を定義します。

 

 

板ポリゴンをズームアップするため、カメラの設定値を修正します。

画角とカメラの位置に注目してください。

 

 

updateメソッドは、描画前に処理されるメソッドです。

count は頂点シェーダで利用する時間の代わりに使用します。描画されるタイミングでカウントアップします。

 

 

updateメソッドで算出した count 変数を頂点シェーダへ連携するための処理を追加します。「unif_pm」と同様の設定です。

 

波の広がりを算出するための処理は以上です。

波紋の実行

それでは、シミュレータを起動してみましょう!

シミュレータを起動すると、波紋が画面に描画されます。

 

image00

 

※動画を作ってみました!こちらから動画を見れます。

まとめ

今回は、波紋をテーマにObjective-CとOpenGL でプログラムを書いてみました。

 

OpenGLの開発は、最初に理解しなければいけないことが多いように感じました。

 

例えば、Javaで最初に学ぶことは、『Hello World !』をコンソールに出力することです。これは、数行あれば完成します。おまじないが1行、『Hello World !』の出力が1行です。

 

OpenGLは、まずはOpenGLの言語仕様、初期化から描画までの流れを理解しなければなりません。

さらに動きのあるポリゴンを作成するとなるとカメラ、光、影をベクトル、行列によって計算しなければなりません。

さらに、複雑な動きになると、高レベルな数学の知識が必要になります。

 

Javaとは違い、OpenGLは最初に乗り越えないといけない壁が高いと思います。

 

ですが、エンジニアとして、自由に描画できるOpenGLの魅力は尽きません。また、提供されるライブラリなどでは限界があります。

必要な時に、求められることができるようになるためには知識が必要です。

そのためには、OpenGLのような低レベル言語を経験し、エンジニアとしての底力を上げておきましょう!

バックナンバー

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2

OpenGL ES2.0で波紋を作る#3 プロジェクト作成

OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成

OpenGL ES2.0で波紋を作る#5 格子状の板ポリゴンを作る

OpenGL ES2.0で波紋を作る#6 カメラをつける

OpenGL ES2.0で波紋を作る#7 板ポリゴンに動きをつける

 

OpenGL ES 2.0で波紋を作る#6 カメラをつける

 

前の章で作成した板ポリゴンへのカメラの使い方を解説します。

ポイント

 ・カメラの使い方

カメラの概念

板ポリゴンにカメラをつけるには、OpenGL上でのカメラの使い方を理解しなければなりません。

 

以下、カメラの使い方を解説します。

 ・プロジェクションの設定

 ・カメラ視点の設定

 ・モデルビューの設定

 ・描画

プロジェクションの設定

□ プロジェクションの概念

プロジェクションは、画角、ニアクリップ、ファークリップを利用します。

 

以下の図の青色がカメラから見える範囲です。

image00

 

項目 内容
画角 Y軸に対する視野領域の角度。
radianを設定します。
ニアクリップ カメラ視点から最初に見える距離。
nearを設定します。
ファークリップ カメラ視点から最後に見える距離。
farを設定します。

□ プロジェクションの設定

カメラのプロジェクションの設定は、「GLKMatrix4MakePerspective」を利用します。

 

GLKMatrix4MakePerspectiveの引数は、下記の通りです。

第1引数:ラジアン。GLKMathDegreesToRadiansを利用することで、度数からラジアンに変換できます。

第2引数:画面のアスペクト比

第3引数:ニアクリップ

第4引数:ファークリップ

□ カメラ視点の概念

カメラの視点の概念

カメラ視点には、カメラのベクトル、カメラの位置、ターゲットの位置を設定します。

 

image01

 

項目 内容
カメラの位置 カメラの位置座標。
eyeX、eyeY、eyeZを設定します。
ターゲットの位置 カメラから見るターゲットの位置座標。
targetX、targetY、targetZを設定します。
カメラのベクトル カメラの方向。
upX、upY、upZを設定します。

カメラ視点の設定

カメラ視点の設定は、「GLKMatrix4MakeLookAt」を利用します。

 

GLKMatrix4MakeLookAtの引数は、先頭から順にカメラの位置座標、ターゲットの位置座標、カメラのベクトルの座標を設定します。

□ モデルビュー

頂点シェーダへ連携するためのモデルビューを算出します。

モデルビューは、カメラのプロジェクションとカメラの視点の情報を掛けあわせた情報です。

モデルビューの設定

モデルビューの設定は、「GLKMatrix4Multiply」を利用します。

 

GLKMatrix4Multiplyは、行列の掛け算を行います。カメラのプロジェクション情報とカメラの視点情報を引数に渡します。

その後、頂点シェーダ側で頂点情報と掛け合わすことでカメラの視点になります。

□ 描画

頂点シェーダ内のデータアクセス

頂点シェーダ内のデータへアクセスするには、「glUniformMatrix4fv」を利用します。

これで、頂点シェーダが保持する「unif_pm」変数に外部からアクセスできるようになります。

カメラの作成

□ カメラの作成

前の章で作成したrepercussionsプロジェクトに対して、以下のファイルを修正します。

 ・Shader.vsh

 ・GameViewController.m

 

変更箇所について解説します。

変更箇所は、背景を反転させています。

Shader.fsh

 

カメラ情報は uniform で宣言した変数を利用します。uniform を宣言した unif_pm は、外部からカメラ情報を設定することができます。

※uniform は、attribute とは異なり宣言する数に制限があります。ご注意ください。

 

gl_Position は、頂点情報とカメラ情報を掛けあわせた情報を受け取ります。

GameViewController.m

 

描画時にOpenGLへ連携するモデルビューを宣言します。

 

 

setupGLメソッドでは、カメラの初期化処理を追加します。

 

カメラの初期化は、カメラのプロジェクション、カメラ視点を設定し、そこからモデルビューを算出します。

カメラのプロジェクション、カメラ視点、モデルビューは、上記で説明した内容と同じです。

 

ここでの注意点は、カメラの設定には微調整が必要になることです。

カメラの向き、視点の範囲、距離などが適切に設定されないと対象物を見失うことになります。

例えるならば、カメラのファインダーと同じイメージです。

 

 

glkViewメソッドでは、頂点シェーダにカメラ情報を連携するための処理を追加します。

カメラの実行

シミュレータを起動すると、カメラ視点から眺めた板ポリゴンが画面に描画されます。

 

image02

 

次回は、最終章です。

このカメラつき板ポリゴンに対して、時間に応じて高さを設定すると波紋が完成します。

バックナンバー

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2

OpenGL ES2.0で波紋を作る#3 プロジェクト作成

OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成

OpenGL ES2.0で波紋を作る#5 格子状の板ポリゴンを作る

OpenGL ES2.0で波紋を作る#6 カメラをつける

 

OpenGL ES 2.0で波紋を作る#3 プロジェクト作成

 

この章では、OpenGLを利用したプロジェクト作成方法を解説します。

ポイント

 ・OpenGLを利用したプロジェクトの作成方法

プロジェクト作成手順

この記事を作成している時点では、最新のXcodeのバージョンは、6.3.2です。

今後、Xcodeのバージョンアップに伴い、記事通りの手順では進めることができないかもしれません。別途、Apple公式のデベロッパーページにて、ご確認をお願いします。

 

プロジェクト作成の手順は、以下の流れになります。

 1. Xcode起動

 2. 新規プロジェクト

 3. シミュレータ起動

1. プロジェクト起動

メニューよりプロジェクトを起動します。

以下は、「Spotlight 検索」からXcodeを起動しています。

image01

※Xcodeがない場合、AppleStoreにて「Xcode」を検索し、最新版をインストールしてください。

2. 新規プロジェクト

□ 新規プロジェクト作成

メニュー→ファイル→New→Project…をクリックします。

image02

 

iOS→Application→Game

image03

 

プロジェクトの作成では、Gameプロジェクトを選択します。

Gameプロジェクトは、OpenGLが既に設定されており、コントローラーやビューの面倒な設定を省くことができます。

□ プロジェクトの設定

以下の入力項目のポイントは、「Game Technology」に「OpenGL ES」 を利用することです。

image04

 

入力内容

項目 内容
Product Name 任意の内容を設定してください。
例)repercussions
Organization Name 任意の内容を設定してください。
例)sample
Organization Identifier 任意の内容を設定してください。
例)sample
Langueage Objective-C
Game Technology OpenGL ES
Device iPhone

 

以上で、Gameプロジェクトが作成できます。

3. シミュレータ起動

Xcodeからシミュレータを起動します。

メニュー→▶ボタン→シミュレータ起動

image05

 

image06

※初回は、起動に時間がかかることがあります。

 

シミュレータは、初期サイズが大きいので、画面に合わせて縮小してください。

メニュー→Window→Scale→50%

image07

 

image08

その他

OpenGLは、GPUを利用することで高速に描画できるライブラリです。

シミュレータはGPUを利用しません。もし、実機が利用できる環境であれば、実機を利用した方がOpenGLの良さを理解しやすいと思います。

バックナンバー

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2

OpenGL ES2.0で波紋を作る#3 プロジェクト作成

 

OpenGL ES 2.0で波紋を作る#5 格子状の板ポリゴンを作る

 

この章では、波紋の元になる格子状の板ポリゴンの作成について解説します。

ポイント

 ・板ポリゴン

 ・縮退三角形

板ポリゴン

ポリゴンとは、立体的な物体を表現するための多角形のことを言います。

 

OpenGLは三角形を利用して多角形を作成します。四角形は三角形を2つ組み合わせ、五角形は3つ組み合わせることで作成できます。

OpenGLのポリゴンも同様に、複数の三角形を組み合わせることで多角形を作成し、立体を表現します。この三角形を組み合わせて、2Dのポリゴンを作成します。ここでは、この2Dポリゴンを「板ポリゴン」と呼びます。

 

今回、板ポリゴンは以下の設計で作成します。

 ・1つの四角形を細かく分割する

 ・分割した四角形から、三角形を作るための頂点を算出する。

 ・頂点をベースに三角形を作成する

 ・一つ一つの三角形に色を塗る

板ポリゴン作成

前の章で作成したrepercussionsプロジェクトに対して、以下のファイルを修正します。

 ・Shader.vsh

 ・Shader.fsh

 ・GameViewController.m

 

変更箇所について解説します。

変更箇所は、背景を反転させています。

Shader.vsh

Shader.vshファイルは、頂点シェーダです。絵を描くための処理を記載します。

 

頂点情報は attribute で宣言した変数を利用します。attributeを宣言した attr_pos は、外部から頂点情報を設定することができます。

 

varying で宣言した vary_color は、頂点シェーダからフラグメントシェーダに情報を連携するための変数です。この後に呼ばれるフラグメントシェーダに色情報を連携します。

 

gl_Position は、OpenGLの変数です。頂点シェーダから頂点情報を受け取ります。

Shader.fsh

Shader.fshファイルは、フラグメントシェーダです。色を塗るための処理を記載します。

 

フラグメントシェーダでは、頂点情報のように attribute を利用することが出来ません。

そのため、varying にて宣言した vary_color を利用し、頂点シェーダから色情報を受け取ります。

GameViewController.m

「OpenGL ES を組み込むベースを作成」 で説明した修正の必要なメソッドと宣言部について解説します。

以下の修正以外は、そのままです。

 

 

クラスの宣言部では、波紋の作成に必要な構造体の宣言、定数、インスタンス変数を定義します。

 

VertexData は、頂点情報を格納するための構造体です。

 

kDivCount、kVertexCount、kIndexCount は、バッファ作成や描画時に利用するための定数です。

kDivCount は、1枚の四角形を格子状に分割するための数です。

kVertexCount は、格子状に分割した頂点の数です。

kIndexCount は、IBOで利用する頂点のインデックスの数です。

 

インスタンス変数として、頂点バッファとインデックスバッファの変数を定義します。

 

 

setupGLメソッドでは、描画に必要なVBO、IBOを作成します。

 

頂点バッファ/インデックスバッファ作成、バインド、バッファデータのアップロードは、「基礎知識2」(シェーダの効率的な描画) で解説した内容と同じです。

 

VBOには、頂点情報を設定します。

頂点情報は、VertexDataの配列(vertrices)を利用します。

 

頂点毎に頂点の座標(x、y、z)と色(u、v)を算出し、VertexDataに設定し、それを配列へ格納します。

 

頂点の座標は、頂点の分割数と頂点間の長さから算出します。

 

色は、頂点の座標を利用します。今回は、x座標とy座標をRGBカラーのRとGとして設定します。

 

 

IBOは、glDrawElements呼び出し際、GL_TRIANGLE_STRIPモードで描画されます。

GL_TRIANGLE_STRIPモードは、次の1点と前の2点の頂点を利用して三角形を描くモードです。

ここでは、この頂点を算出する処理を記載しています。

 

IBOは、頂点バッファの頂点情報のインデックスを設定します。この設定には数値の配列(indices)を利用します。

 

頂点情報のインデックスは、頂点の分割数を元に算出します。

現在のy座標を視点に、x座標から頂点バッファの頂点情報のインデックスを設定します。

その後、次のy座標を算出し、同じように頂点情報のインデックスを設定します。

 

ここでポイントになるのが、y座標が変わるタイミングです。

x座標の終わりと次のx座標の始まりが繋がるため、無駄な三角形が描画されます。

この繋がりを描画させないための処理として、縮退三角形を利用します。

 

縮退三角形については、後半部分で解説します。

 

 

tearDownGLメソッドは、シェーダをメモリから開放する処理を記載します。

 

setupGLメソッドで作成したVBO、IBOを削除します。

 

 

 

updataメソッドは、今回、使用しません。

 

不要な処理を削除します。

 

 

glkViewメソッドでは、初期化時に作成したVBOとIBOをバインドします。そして、画面に板ポリゴンを描画します。

 

頂点情報設定、フラグメント情報設定、描画は、「基礎知識2」(シェーダの効率的な描画) で説明した内容と同じです。

縮退三角形

今回、板ポリゴンを作成するためGL_TRIANGLE_STRIPモードで描画しています。このモードは、縮退三角形を描画しない特徴があります。

 

縮退三角形とは、面積が0の三角形、または、3点の座標が直線に並ぶ三角形のことを言います。

 

image01

 

通常、GL_TRIANGLE_STRIPモードで描画すると上の図のような順番でポリゴンが描かれます。このポリゴンは、2つの三角形で四角形を描いています。

 

image02

 

次に、1つの四角形を2分割し、8つの三角形で四角形を描きます。

 

image03

 

ポイントは、2→5→3の三角形です。

GL_TRIANGLE_STRIPモードの仕様上、次の1点と前の2点を利用して三角形を描くため、2→5→3の三角形が描かれます。

この三角形が描かれると、波紋が綺麗に表示されなくなります。

 

この2→5→3の三角形を描画しないためには、どうすれば良いのでしょうか?

 

それを解決するのが、縮退三角形です。

 

縮退三角形を利用する箇所は、以下です。

 1. y座標が変わるタイミングのx座標の終わり

 2. y座標が変わるタイミングのx座標の始まり

 

修正方法は、以下を追加するだけです。

 1. y座標が変わるタイミングのx座標の終わり

  x座標の最後の頂点の位置に、同じ頂点を1つ追加します。

   → 以下の図のindices[6]です。

 2. y座標が変わるタイミングのx座標の始まり

  x座標の最初の頂点の位置に、同じ頂点を1つ追加します。

   → 以下の図のindices[8]です。

 

これにより縮退三角形が作成され、不要な三角形が描画されなくなります。

image04 image05

板ポリゴンの実行

シミュレータを起動すると、板ポリゴンが画面に描画されます。

 

image06

 

次回は、この板ポリゴンにカメラをつけます。

カメラをつけることで、3D視点から板ポリゴンを眺めることができます。

バックナンバー

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2

OpenGL ES2.0で波紋を作る#3 プロジェクト作成

OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成

OpenGL ES2.0で波紋を作る#5 格子状の板ポリゴンを作る

 

OpenGL ES 2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成

 

この章では、作成したrepercussionsプロジェクトの理解と波紋を作るためのrepercussionsプロジェクトの変更方法について解説します。

ポイント

 ・repercussionsプロジェクトの理解

 ・プロジェクトの変更方法

repercussionsプロジェクトの理解

repercussionsプロジェクトは、既に「OpenGL ES」が取り込まれたプロジェクトです。

各メソッドで「OpenGL ES」がどのように処理しているかを確認しましょう。

repercussionsプロジェクト

プロジェクトを新規作成すると、以下のクラスが自動生成されます。

 

repercussions

 |_AppDelegate.h

 |_AppDelegate.m

 |_Shader.fsh

 |_Shader.vsh

 |_GameViewController.h

 |_GameViewController.m

 |_Main.storyboard

 |_Images.xcassets

 |_LaunchScreen.xib

 |_Supporting Files

 |  |_Info.plist

 |  |_main.m

 |_repercussionsTests

 |_Products

   |_repercussions.app

   |_repercussionsTests.app

 

このプロジェクトでは、GameViewControllerクラスが描画処理のメインクラスになっています。このクラスを理解すれば、OpenGLの流れが更に理解できると思います。

 

では、GameViewControllerクラスの各メソッドにどのような処理を記載しているのか解説します。

・GLKViewController main methods

No. メソッド 内容
1 (void)viewDidLoad UIViewControllerのライフサイクルにおいて、initの後に呼ばれるメソッドです。
アプリ起動後、Viewが初めて呼び出される際に1回だけ呼ばれます。このタイミングで、シェーダの初期化を行います
2 (void)dealloc メモリ解放時に呼ばれるメソッドです。
ARC(Automatic Reference Counting)にて、コンパイラが適切な場所に、このdeallocメソッドを挿入します。
今回は、OpenGLで利用しているリソースを開放します。
3 (void)didReceiveMemoryWarning メモリ不足が発生した際に呼ばれるメソッドです。
メモリ不足が発生した場合、OpenGLで利用しているリソースを開放します。
4 (BOOL)prefersStatusBarHidden ステータスバーを非表示にするメソッドです。
戻り値をtrueにすることで、ステータスバーが非表示になります。
5 (void)setupGL シェーダを初期化するメソッドです。
6 (void)tearDownGL シェーダをメモリから開放するメソッドです。

・GLKView and GLKViewController delegate methods

No. メソッド 内容
7 (void)update 処理を更新するメソッドです。
描画しませんが、描画するための計算などを事前に行います。
8 (void)glkView:(GLKView *)view drawInRect:(CGRect)rect Viewを描画するメソッドです。
シェーダで記載した内容が描画されます。

・GLKViewController main methods

No. メソッド 内容
9 (void)viewDidLoad シェーダをロードするためのメソッドです。
内部では、Shader.vsh、Shader.fshをロードします。
10 (void)dealloc ロードしたシェーダをコンパイルするためのメソッドです。
11 (void)didReceiveMemoryWarning プログラマブルシェーダにリンクするためのメソッドです。
12 (BOOL)prefersStatusBarHidden OpenGLが実行可能かどうかをチェックするためのメソッドです。

□ OpenGL ESの初期化

「OpenGL ES」を利用するには、EAGLContextが必要になります。

 

EAGLContextは、Apple公式サイトのリファレンスに以下のように記載されています。(※1)

An EAGLContext object manages an OpenGL ES rendering context—the state information, commands, and resources needed to draw using OpenGL ES. To execute OpenGL ES commands, you need a current rendering context.

「OpenGL ES Framework Referenceより抜粋」

EAGLContextオブジェクトは、OpenGL ESのレンダリングコンテキスト(OpenGL ESを使用して描画するのに必要なリソースやコマンド、状態情報)を管理します。OpenGL ESコマンドを実行するには、現在のレンダリングコンテキストが必要になります。

 

つまり、EAGLContextが描画に必要な情報を管理しているクラスであり、描画スレッドに管理されたEAGLContextがなければ、OpenGLコマンドは実行することができないことになります。

 

このEAGLContextクラスのポイントは、オブジェクトの初期化と描画スレッドの管理です。

EAGLContext初期化

EAGLContextは、No.1のviewDidLoadメソッド内で初期化しています。

 

今回は、「OpenGL ES 2.0」を利用するため、「kEAGLRenderingAPIOpenGLES2」の定数を設定しています。

「OpenGL ES」のバージョンによって、この定数は変わります。

OpenGL ESのバージョン 定数
1.x kEAGLRenderingAPIOpenGLES1
2.x kEAGLRenderingAPIOpenGLES2
3.x kEAGLRenderingAPIOpenGLES3

描画スレッドの管理

EAGLContextのリファレンスにも記載されていますが、OpenGLコマンドを実行するには、現在のレンダリングコンテキストが必要になります。

現在のレンダリングコンテキストにEAGLContextを設定するには、EAGLContextの「setCurrentContext」を利用します。

 

※OpenGLコマンドを実行する前に現在のレンダリングコンテキストに設定しますが、No.7のupdate、No.8のglkViewメソッドでは、現在のレンダリングコンテキストが設定されている状態で実行されるため、設定する必要はありません。

□ シェーダの初期化、破棄、更新、描画

EAGLContextを初期化した後は、シェーダの初期化と破棄、そして、描画処理の更新と描画を行います。

 

ここでは、OpenGLがどのように利用されているかがポイントになるため、各メソッド内に記載された処理については詳細な説明を省きます。

 

ただし、前回説明した#1「基礎知識1」(シェーダの初期化)、#2「基礎知識2」(シェーダの効率的な描画)の内容と同じような内容になっています。そちらと合わせて確認してください。

シェーダの初期化

シェーダの初期化は、No.5のsetupGLメソッド内で実施します。

 

setupGLメソッドは、以下を処理しています。

 ・シェーダオブジェクトの作成(ロード)とコンパイル

 ・プログラマブルシェーダへのリンク

 ・頂点情報設定

 ・バッファの作成とアップロード

 ・バッファのバインド、アンバインド

 ・頂点情報の利用箇所指定

シェーダの破棄

シェーダの破棄は、No.6のtearDownGLメソッド内で実施します。

 

tearDownGLメソッドは、以下を処理しています。

 ・バッファの削除

 ・プログラマブルのリンク削除

更新

更新は、No.7のupdateメソッド内で実施します。

 

updateメソッドは、以下を処理しています。

 ・座標再計算(四角形、カメラ)

描画

描画は、No.8のglkViewメソッド内で実施します。

 

glkViewメソッドは、以下を処理しています。

 ・カラー設定

 ・バッファのバインド

 ・座標アップロード

 ・描画

repercussionsプロジェクトの変更方法

repercussionsプロジェクトには、12メソッドが定義されていますが、そのうち4メソッドを変更することで、今回のテーマである波紋のメイン処理を作成することができます。

 

その4メソッドは、シェーダの初期化、破棄、更新、描画で説明したメソッドになります。

それ以外のメソッドは、ほとんどがそのまま利用できます。

 

No. メソッド 内容
5 (void)setupGL シェーダを初期化するメソッドです。
6 (void)tearDownGL シェーダをメモリから開放するメソッドです。
7 (void)update 処理を更新するメソッドです。
描画しませんが、描画するための計算などを事前に行います。
8 (void)glkView:(GLKView *)view drawInRect:(CGRect)rect Viewを描画するメソッドです。
シェーダで記載した内容が描画されます。

 

次回は、いよいよ波紋作成です。

波紋を作成するための基礎である板ポリゴンを作成します。

参考

※1・・・「EAGLContext」については、OpenGL ES Framework Reference の EAGLContext を参照してください。

バックナンバー

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2

OpenGL ES2.0で波紋を作る#3 プロジェクト作成

OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成

 

「ナレッジボックス」に「OpenGL ES 2.0で波紋を作る(その1)」を追加!

 opnGL_title

 

クロノスの技術ノウハウをまとめた「ナレッジボックス」に「OpenGL ES 2.0で波紋を作る」を追加しました。

https://www.kronos.jp/technologies/knowledge/knowledge-1/2528.html

 

ナレッジボックスでは、クロノスで過去に開発したシステムやアプリケーションで実装した技術ノウハウを掲載しています。
今回は「OpenGL ES2.0で波紋を作る」の全7章のうち、プロローグ・1・2章を公開しました。

 

クロノスでは、このナレッジボックスに掲載している技術を再利用可能なライブラリやコンポーネントにすることにより、請負開発を徹底的に効率化し、高品質化、低コスト化を実現しています。 掲載している技術やノウハウが、もし御社で開発予定のシステムやアプリケーションで活用できそうでしたら、ぜひ一度ご相談ください。

 

 

OpenGL ES 2.0で波紋を作る

 

opnGL_title

プラットフォーム: iOS

はじめに

 最近のスマートフォンは、高性能な処理能力、低消費電力、そして、ハイパフォーマンスなグラフィック能力など、とても素晴らしい進化を遂げています。

その起因となったのは、Apple社のモバイルデバイス「iPhone」です。

 

 iPhoneはいくつものバージョンアップを繰り返し、現在は、iPhone6sが発売されています。

特にiPhone5からCPU能力に加えGPU能力が大幅に向上したことで、3Dグラフィックを意識したプログラミングがとても身近になりました。

 

 3Dグラフィックプログラミングは、「OpenGL(※1)」で実現できます。

また、iPhoneのようなモバイルデバイスでも利用できる「OpenGL ES」もバージョンアップされ、今まではゲーム開発者しか出来なかったことが容易にできるようになりました。

 

 そこで、今回、iPhoneとOpenGL ESを利用して、3Dグラフィックプログラミングを試してみることにしました。

テーマは、

  •  ・滑らかに動くこと
  •  ・連続性があること

にしました。

具体的には、自然界に存在する動き「波紋」です。

見た目は簡単に見えますが、プログラミングを用いて実現するにはとても良いテーマだと思います。

 

 波紋を作るためのOpneGL ESの前提知識、そして、プロジェクトを作成し波紋を作るまでの流れを解説します。

Agenda

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2

OpenGL ES2.0で波紋を作る#3 プロジェクト作成

OpenGL ES2.0で波紋を作る#4 OpenGL ES を組み込むベースを作成

OpenGL ES2.0で波紋を作る#5 格子状の板ポリゴンを作る

OpenGL ES2.0で波紋を作る#6 カメラをつける

OpenGL ES2.0で波紋を作る#7 板ポリゴンに動きをつける

参考

※1・・・OpenGLは、Khronosグループが策定したオープンソースなグラフィックライブラリです。

 

OpenGL ES 2.0で波紋を作る#1 前提知識1

 

前提知識1では、OpenGL ES 2.0の特徴でもあるシェーダについて、その初期化手順を解説します。

ポイント

 ・シェーダ

 ・頂点シェーダ

 ・フラグメントシェーダ

 ・頂点シェーダとフラグメントシェーダのリンク

シェーダとは

OpenGLは、オープンソースなグラフィックライブラリです。

その特徴は、GPU(グラフィックに必要な計算処理を得意とする演算装置)を利用して高速な描画が行える点です。

 

OpenGLを組み込み専用のライブラリにしたのがOpenGL ES(以降、OpenGLと呼ぶ)です。バージョン2.0(※1)からシェーダを記述できるようになり、高度な描画処理が実現できるようになりました。

 

「シェーダ」をネットで調べると難しい説明ばかりで理解するのが難しいのですが、著者なりにひとことで表現すると「シェーダとは、OpenGL専用言語を使って、GPUに命令を送るためのプログラミングの集まり」だと言えます。

シェーダの初期化

シェーダは、頂点シェーダとフラグメントシェーダの2種類のシェーダがあります。

頂点シェーダによって絵を描き、フラグメントシェーダによって色を塗るイメージです。

 

以下は、シェーダを初期化するまでの基本的な流れです。

 1. ソース作成

 2. シェーダ

 3. オブジェクト作成

 4. コンパイル

 5. プログラマブルシェーダ作成

 6. アタッチ

 7. リンク

 

1〜3.において、頂点シェーダ、フラグメントシェーダをそれぞれ作成し、

4〜6.で2つのシェーダオブジェクトをプログラマブルシェーダにアタッチし、その後、リンク付けをします。

これで、頂点シェーダとフラグメントシェーダーはプログラマブルシェーダから利用できるようになり、シェーダの初期化が完了します。

頂点シェーダ

□ ソース作成

シェーダの中身は、GLSL ES(OpenGL Shader Language ES)(※2)言語に従って記述します。

それ以外のOpenGLの呼び出し部分は、Objective-C(または、Swift)にて記述します。

 

以下のコードは、外部(レンダリングするに頂点情報を渡す)から受け取った頂点の位置をOpenGLに連携するプログラムです。

□ シェーダオブジェクト作成とコンパイル

作成したシェーダのソースは、コンパイルしなければ動かすことはできません。

ソースを読み込んだ後、オブジェクト化し、コンパイルします。

 

シェーダは、直接ソースに文字列として記述したり、別ファイルに記述し、そのファイルを読み込むことでロードすることもできます。

どちらでも構いません。どちらであっても、文字列としてOpenGLに渡す必要があります。

 

シェーダのオブジェクト化には、「glShaderSource」を利用します。

glShaderSourceの第3パラメータには、ソースのポインタを渡すことに注意してください。(※3)

 

シェーダのコンパイルは、「glCompileShader」を利用します。

フラグメントシェーダ

基本的には、頂点シェーダと同じです。

異なるのは、シェーダの内容がカラーをメインに記述することになる点です。

 

以下のコードは、白色で画面を塗りつぶすことをOpenGLに連携するプログラムです。

※オブジェクト作成、コンパイルは、頂点シェーダと同じです。

頂点シェーダとフラグメントシェーダのリンク

□ プログラマブルシェーダへのリンク

OpenGLがシェーダを利用するためには、プログラマブルシェーダが必要になります。

 

作成したプログラマブルシェーダに、コンパイルした頂点シェーダとフラグメントシェーダをアタッチし、その後、プログラマブルシェーダをOpenGLにリンク付けます。

これで、OpenGLが頂点シェーダ、フラグメントシェーダを利用できるようになります。

 

プログラマブルシェーダの作成は、「glCreateProgram」を利用します。

シェーダのアタッチは、「glAttachShader」を利用します。

 

最後に、OpenGLにプログラマブルシェーダを関連付けるため、リンクを貼ります。

□ シェーダ削除

glLinkProgramを利用しリンク済みにした後、頂点シェーダ、フラグメントシェーダーは削除してください。

 

シェーダの削除は、「glDeleteShader」を利用します。

【参考】

※1・・・「OpenGL ES 2.0」については、OpenGL ES 2.0 Reference Pagesを参照してください。

 

※2・・・「GLSL ES」については、OpenGL ES Shading Languageを参照してください。

 

※3・・・説明ポイントを絞り込むため、エラー処理を記述に含めておりません。本来は、OpenGL ESのAPIを呼び出した後にエラー処理を記述し、デバッグできるようにします。

バックナンバー

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2

OpenGL ES 2.0で波紋を作る#2 前提知識2

 

前提知識2では、シェーダの効率的な描画について解説します。

【ポイント】

 ・VBO

 ・IBO

 ・描画

【効率的な描画】

OpenGLには効率の良いデータ転送があります。これは、高速に描画するためには重要なデータ転送方式です。

 ・VBO(Vertex Buffer Object)・・・ 頂点バッファオブジェクト

 ・IBO(Index Buffer Object) ・・・ インデックスバッファオブジェクト

 ・VAO(Vertex Array Object) ・・・ 頂点情報と状態を保持するオブジェクト

  など

 

今回は、VBO、IBOについて解説します。

 

【VBO】

あらかじめVRAM(GPUが利用できるメモリ領域)に頂点情報を転送することで、その後に発生する無駄なデータ転送を減らします。これにより効率的な描画ができます。

 

【IBO】

ポリゴンを作成すると、重複する頂点情報が多く作成され無駄なデータが発生します。

IBOは、頂点情報に番号(インデックス)を付けて、描画時にその番号を指定することで重複するデータをなくします。これにより効率的な描画ができます。

 

VBOとIBOを取り入れることで、VBOであらかじめ頂点情報を設定しておき、IBOで頂点情報を効率よく利用することができます。

VBO

VBOは、バッファオブジェクトを作成し、バッファをバインドし、頂点情報をVRAMへアップロードすることで利用できます。

 

※バッファオブジェクトの作成〜アップロードは、前提知識1で説明したシェーダの初期処理に含めて作成します。

□ 頂点バッファ作成

バッファオブジェクトの作成は、「glGenBuffers」を利用します。

glGenBuffersの第2パラメータに、ソースのポインタを渡すことに注意してください。

□ バインド

バッファを有効にするには、バッファをバインドします。

 

バッファのバインドには、「glBindBuffer」を利用します。

glBindBufferの第1パラメータには、VBO、IBOを判断するための定数を渡します。

 ・VBOの場合:GL_ARRAY_BUFFER

 ・IBOの場合:GL_ELEMENT_ARRAY_BUFFER

□ バッファデータのアップロード

バッファをバインドすることで、VRAMへ頂点情報をアップロードできます。

 

アップロードには、「glBufferData」を利用します。

glBufferDataの第2引数は、アップロードするデータのバイト数です。オブジェクトのサイズとオブジェクト数を掛けた結果になります。

第3引数には、アップロードするデータのポイントを設定します。

第4引数には、データの利用方法を指定します。GL_STATIC_DRAWは、一度だけアップロードしますが、アップロードしたデータは利用制限なしで再利用できます。

□ バインド解除

VRAMへアップロードした後、バインドを解除します。

 

バインドの解除には、「glBindBuffer」を利用します。

バインドと同じですが、第2引数に0を設定します。0を設定することで、バインドが解除されます。

IBO

基本的にバッファオブジェクトと同じです。

異なるのは、それぞれの第1引数がIBOの設定であるGL_ELEMENT_ARRAY_BUFFERになるところです。

 

※インデックスバッファの作成、バインド、バッファデータのアップロード、バインド解除は、バッファオブジェクトと同じです。

描画

VRAMへアップロードしたバッファオブジェクトを利用し、描画するための処理を解説します。

 

VBOを用いた描画は、以下の流れになります。

 1. 頂点情報の設定

   1.1. 頂点情報のデータ準備

   1.2. 頂点シェーダ内のデータアクセス許可

   1.3. 頂点情報の利用箇所指定

 2. フラグメント情報の設定

   2.1. フラグメント情報のデータ準備

   2.2. フラグメントシェーダ内のデータアクセス許可

   2.3. フラグメント情報の利用箇所指定

 3. 描画

1. 頂点情報の設定

1.1. 頂点情報のデータ準備

シェーダ内の属性に対して動的に値を設定するためには、外部からシェーダ内の変数にアクセスできるように設定する必要があります。

 

外部からのアクセスさせるためのデータ準備には、「glGetAttribLocation」を利用します。

1.2. 頂点シェーダ内のデータアクセス許可

シェーダ内のデータへアクセスするには、「glEnableVertexAttribArray」を利用します。

これにより、頂点シェーダが保持する「attr_pos」変数に外部からアクセスできるようになります。

1.3. 頂点情報の利用箇所指定

はじめにバッファを再バインドします。次に、頂点情報の利用箇所を指定します。

バッファをバインドしなければ、VRAM上にアップロードしたバッファを利用することはできないので注意してください。

 

バッファをバインドしていることを前提にした「glVertexAttribPointer」の設定について解説します。

 

OpenGLは、この利用箇所の指定を元に描画するためのアクセス領域を確定させます。

頂点情報の利用箇所の指定は、先ほど説明したシェーダの「attr_pos_value」変数に対して、バッファの利用箇所を指定します。

 

glVertexAttribPointerの引数は、以下の通りです。ポイントは、いずれもVBOを利用している点です。

第1引数:頂点シェーダの属性と関連付けられたインデックス

第2引数:バインドしたVBOの頂点の要素数(今回は、x座標、y座標、z座標の3要素)

第3引数:バインドしたVBOの頂点情報の型

第4引数:正規化有無(GL_FALSE:正規化しない)

第5引数:バインドしたVBOのサイズ

第6引数:バインドしたVBOの先頭のオフセット

2. フラグメント情報の設定

フラグメント情報の設定は、基本的に「頂点情報の設定」と同じです。

2.1. フラグメント情報のデータ準備

フラグメント情報のデータ準備も頂点情報と同様です。「attr_color」に注目してください。

2.2. フラグメント情報へのアクセス許可

フラグメント情報へのアクセス許可も頂点情報と同様です。「attr_color」に注目してください。

2.3. フラグメント情報の利用箇所指定

glVertexAttribPointerの第6引数には、バインドしたVBOの先頭のオフセットを指定します。

ここではVertexDataの最初が頂点情報のため、その次からカラーデータであることを指定しています。

3. 描画

バッファを利用した描画は、「glDrawElements」を利用します。

「glDrawElements」を利用する前に、バッファをバインドしければなりません。

 

頂点情報、フラグメント情報の設定には、VBOを指定しました。

描画は、VBOで設定した情報をIBOを利用して描画します。

 

IBOには、GL_ELEMENT_ARRAY_BUFFERを指定します。

 

次は、描画の設定です。

 

glDrawElementsの引数は、以下の通りです。ポイントは、いずれもIBOを利用している点です。

第1引数:レンダリングモード。GL_TRIANGLE_STRIPは、連続した三角形を描画するモードです。

第2引数:バインドしたIBOの頂点情報の数

第3引数:バインドしたIBOの型

第4引数:バインドしたIBOの先頭のオフセット

 

上記は、頂点情報を用いて連続した三角形を描きます。

 

連続した三角形は、頂点情報の数が多くなればなるほど滑らかなになり、逆に頂点情報が少なければ少ないほど角が目立つようになります。

 

これにより、効率的に描画できます。

 

以上で、効率的な描画処理の解説は終わりです。

バックナンバー

OpenGL ES2.0で波紋を作る#1 前提知識1

OpenGL ES2.0で波紋を作る#2 前提知識2