ふぅああああああああああ!!
やっとお仕事終わったァ・・・
オエ━━━━━━(´Д`|||)━━━━━━!!!!
先週は徹夜4日、お外に出るのはお昼休憩の1時間のみ。
この数週間はこの世の絶望を見た気がしますよ。
実際に幻聴や幻覚も見たというのは秘密です♡
さすがプログラマという職業。
まさに社畜。
社会のイベリコ豚だわ。
豚って嬲って!! 嬲ってちょうだい!! ( ‘д‘⊂彡☆))Д´) パーン
ぶひいいいいいいいいいいいいいいいいいいいい!!!!!!!!!!!!!!
ーーーー【徹夜して学んだこと】ーーーー
徹夜明けのテンションってすごいですね。
【仕事が終わらないストレス + 徹夜】
という相乗効果によりわたくしの精神は二段階以上ドス黒く染まりました。
朝方には無駄に席をたったり座ったり。
ボールペンでノートに絵と呼ぶには烏滸がましい落書きを嬲り書き、
時には叫び、時には歌い。。。
自分が自分で無くなりそうでした(笑)
いや、ほんと笑い事で済まされる段階で仕事終わってよかったわ・・・・
これが一ヶ月以上も続くと確実に精神ぶっ壊れますね。まじで。
みなさぁーん!
プログラマになろうと思ったら、、、、
相応の覚悟をしてくださいねぇ(威圧)
でも僕はプログラムが大好きなので締め切りに追われてなければとても気持ちよく仕事出来るんですけど・・・(´;ω;`)
いや、まぁ
『会社は選びましょう。』 って話です(`・ω・´)
プログラムが好きならば会社変えよう。
体壊すぐらいなら逃げでもなんでもなくて会社が悪いから。
----------------------------------------
・プログラム好きなんだけど、全然出来ない・・・ 大丈夫なんだろうか・・・
・社会怖すぎワロチョン
----------------------------------------
とか思ってる人は大丈夫。
会社で仕事しているうちにぐわしぐわしスキル育っていきます。
開いた時間に自分がしたいプログラムをすれば全然問題なく強くなります。
僕も会社に入って一日の大半をプログラムに当てることで学生の頃より数段レベルアップした
・・・きがします。 ← わりとまじで心配。
でも学生の方が自分が勉強したいところを重点的に出来るので、
・アルゴリズム。
・自分が好きなジャンルでいいからゲーム制作。
・数学。
は学生のうちにちょろろっっとしとくと社会でても楽です。
はい!
僕は結構疎かにしたので 超苦労してますっ!!(吐血)
アルゴリズム・・・ そう、アルゴリズムなんですよ・・・・・
なんだよリズムって・・・ ラップ刻んでんのかよ・・・・
学生の頃はゲーム制作しかしてなかったからアルゴリズム思考がわかんねええええええええええええええええ!!!!!!!!!!
最適化とかしたくても出来ない → 作業が遅れる → 徹夜
↓
死のサイクル
↓
精神逝っちゃう////
なのでアルゴリズムだけでもいいから学生のうちにやっとこうぜ!
ということです。
僕みたいなksに比べれば大学、専門学校をきちんと行っている人は確実に大丈夫だと思いますぅうううう!
勉強だいじだわー・・・
っと、久しぶりにブログ更新した。
年末までの仕事はぶっ殺したので、色々と溜まっていることブログにをぶっ放していきたいと思います!
【結論】
くりすます?
(URL)前回の続き!!
OpenGL ES の初期化コードは終わったので、
実際に ViewController に描画処理を書いていく(`・ω・´)
・
・
・
・
OpenGL ES の素晴らしき点は、 前回の初期化コードで言うと
BeginScene から EndScene の間だったらどこでも描画処理を書いて良い所です。
CoreGraphics みたいに drawRect 関数のみ とかではないので色々と応用がききます。
今回は ViewController にゲームループを記述して描画処理を書いてみます。
ViewController.h に 必要な変数と関数を書く
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
/** 画面のフレッシュレートと同期する為のクラス **/
CADisplayLink* mpDisplayLink;
}
/**
* ゲームループ
*/
- ( void )GameLoop;
@end
@interface ViewController : UIViewController
{
/** 画面のフレッシュレートと同期する為のクラス **/
CADisplayLink* mpDisplayLink;
}
/**
* ゲームループ
*/
- ( void )GameLoop;
@end
次に ViewController.m の ViewDidLoad に ゲームループをしてもらうようにする
/**
* MainGLView が呼び出された。
*/
- (void)viewDidLoad
{
[super viewDidLoad];
/** スクリーンと同期する **/
// ループ
mpDisplayLink = [ [ UIScreen mainScreen ] displayLinkWithTarget:self selector:@selector( GameLoop ) ];
[ mpDisplayLink addToRunLoop:[ NSRunLoop currentRunLoop ] forMode:NSDefaultRunLoopMode ];
}
CADisplayLink の displayLinkWithTarget に、 "誰の" "どの関数?" を指定して作成し、
addToRunLoop 関数で "ループしてください。" としてやれば
自動的に永遠と
デバイスに最適なループ関数を作ってくれます。
※だいたい60FPS だったと思います。
その間にもタッチイベント等のiPhone機能の取得は可能。
上の例では GameLoop 関数が ぐるぐる呼び出されるようになりました。
※今回は明確にFPSを決めずに描画します。
次に書く描画処理はまた別にでも詳しく書いてみようと思います(`・ω・´)
今回はコードのみです。
でも大体何やってるかはわかると思います。
今回は 正四角形を描画しています。
まず、
OpenGL ESでは三角形が基本の形になりまして、
三角形を12個描画すれば立方体ができ、
頂点を沢山増やせば球体も、
人間モデルさえも描画できます。
誰がなんて言おうともスライムです(本気)
11ポリゴンです。 その名もヌライムですねー
某 FFさんとかで聞く
『3万ポリゴンのモデルや!!!』
俺 :『 ( ゚д゚)! 』 ・・・よくわからん・・・・。
というのは ”3万個三角形を書いて作られたモデル” ということですね。
三角形1つ作る為には頂点が3つ必要です。
頂点を3つ繋げて指定された色でその中を塗りつぶすわけです。 これで三角形。
今回は四角形を描画したい、四角形を三角形で表すには..
【 三角形を2つ書けばいい 】
しかも
その2つの三角形の頂点の内、2つは同じ座標です。
わざわざ 6個頂点を作って描画してもいいのですが、
無駄なことが嫌いなプログラマさんは
========================
前回の三角形に使用した2つの頂点と新しく指定した頂点1つを使用して
次の三角形を作るようにすることができます。
========================
上の画像では、
頂点1, 2, 3 で1つのポリゴンを描画して、
頂点2, 3, 6 でもう一つポリゴンを描画する。 → 頂点は4つで済む。無駄がない
その ”前回の2個の頂点と新しい頂点1つを使用して三角形を描画する方法”
それが TRIANGLE_STRIP と呼ばれる描画方法です。
今回はこれを描画するときに指定します。
そして頂点の色も一緒に設定します。
RGB は 赤、緑、青
A は アルファと言われ、透明色です。
1.0 が最高で 0.0 がその色は全くありません。
Aを0.0にすると見えなくなり、0.5にすると半透明になります。
上記の描画コードを入れた ViewController.m はこんなかんじになります ↓
#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
#import <GLKit/GLKit.h>
#import "MainGLView.h"
@implementation ViewController
/**
* MainGLView が呼び出された。
*/
- (void)viewDidLoad
{
[super viewDidLoad];
#import <QuartzCore/QuartzCore.h>
#import <GLKit/GLKit.h>
#import "MainGLView.h"
@implementation ViewController
/**
* MainGLView が呼び出された。
*/
- (void)viewDidLoad
{
[super viewDidLoad];
/** スクリーンと同期する **/
// ループ
// ループ
mpDisplayLink = [ [ UIScreen mainScreen ] displayLinkWithTarget:self selector:@selector( GameLoop ) ];
[ mpDisplayLink addToRunLoop:[ NSRunLoop currentRunLoop ] forMode:NSDefaultRunLoopMode ];
}
/**
* ゲームループ
*/
- ( void )GameLoop
{
/** 描画準備 **/
// self.view = MainGLView
[ ( MainGLView* )self.view BeginScene ];
/** ここで描画処理 **/
// 頂点座標 頂点情報が4つしかない!
const GLfloat vertics[] =
{
50.0f, 50.0f, // 左上
270.0f, 50.0f, // 右上
50.0f, 270.0f, // 左下
270.0f, 270.0f, // 右下
};
// 頂点色
// 頂点が4つなので色も4つ
const GLfloat colors[] =
}
/**
* ゲームループ
*/
- ( void )GameLoop
{
/** 描画準備 **/
// self.view = MainGLView
[ ( MainGLView* )self.view BeginScene ];
/** ここで描画処理 **/
// 頂点座標 頂点情報が4つしかない!
const GLfloat vertics[] =
{
50.0f, 50.0f, // 左上
270.0f, 50.0f, // 右上
50.0f, 270.0f, // 左下
270.0f, 270.0f, // 右下
};
// 頂点色
// 頂点が4つなので色も4つ
const GLfloat colors[] =
{
// R, G, B, A の順番
1.0f, 0.0f, 0.0f, 1.0f, // 左上
0.0f, 1.0f, 0.0f, 1.0f, // 右上
0.0f, 0.0f, 1.0f, 1.0f, // 左下
1.0f, 0.0f, 1.0f, 1.0f, // 右下
};
/** 頂点情報をOpenGL ESに教える **/
// glVertexPointer( 頂点データのサイズ, データの型, オフセット値(配列の何番目からデータを読み込むか), 座標 )
glVertexPointer( 2, GL_FLOAT, 0, vertics );
/** 頂点座標の配列をセットしたことを OpenGL に教える **/
glEnableClientState( GL_VERTEX_ARRAY );
/** 頂点色も同じ **/
glColorPointer( 4, GL_FLOAT, 0, colors );
glEnableClientState( GL_COLOR_ARRAY );
/** GL_TRIANGLE_STRIP で描画する **/
// glDrawArrays( 頂点をつないでいくルール, オフセット値, 描画する頂点の数 )
glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
/** 描画終了 **/
[ ( MainGLView* )self.view EndScene ];
}
@end
これで頂点4つで四角形が描画されます。
また、
頂点を 描画したい三角形の数 x 3 個作成し、
最初3個の頂点情報で三角形1つ描画、次の頂点情報3個で三角形1つ描画、次の・・・ としていく場合には
GL_TRIANGLES
を指定するとよろしいです。
実際、 GL_TRIANGLES のほうが頭を悩まさずに様々な図形を作成できるので楽です。
そのかわりデータ量を食うというだけ。
他にもいろいろな描画方法があります。
割愛!
と、言うわけで ポリゴンを2つ作成した結果が ↓
ちゃんと思い通りになっとる!!! (`・ω・´)
色もちゃんとグラデーションしてくれてますね!
画像を描画したい場合は、これに画像をぺたぺたと貼り付けるだけでOKです。
画像の貼り方は次にでも....
最初は難しく思いますが、意外に単純です。
3Dだとまた座標系が増えてめんどくさくなりますが2Dではこんなものです。
OpenGL ESを使った高速描画で
ゲームにスリルを与えましょう!!(`・ω・´)
そしてOpenGL ES 使ってるという高揚感で気持ちよくなりましょう。
以上!!!!
今回のプロジェクトを放置してみる ↓
【 (URL)OpenGLES_Test1 】
こんなかの、
OpenGLES_Test1.zip
をクリックして 上の 【ファイル】 → 【ダウンロード】 からオナシャス!!
はい!
真面目に更新して行こうとぉ・・・・、、思います!
iPhoneでアプリを作成する時に画像の描画をしますが、
一度に画面に出す画像の枚数が多くなってくると、思った速度が出ず
に悩んだりすることが出てきます。(多分)
そういう時にGPUをフルに使ってくれる OpenGL ES を使用するのですが、
「 むずい 」 「 めんどくさい 」 「 もういやだ!」
の 3M が襲いかかってきます。
OpenGL ES の敷居が高い!!(半年前のわたくし)
と思われがちですが、実際そうでもないです。 ( 2Dの場合は )
一個ずつ見ていくと初めての方でも意外に簡単だったりするものなので、
時間をかけてゆるりと初期化部分を見ていくことにします
①
現在 IOS6 では 初期化がすこぶる簡単になったそうなので、
今更こんな旧式の初期化は必要ないかと思いますが、
僕は IOS4 時代の初期化方法を調べた時、OpenGL ESが内部で何を行なっているか「なるへそ」と理解し、
感動した気持ちで胸が昂ぶり震えたので多用しています。
なので、旧式のOpenGL ES の初期化方法( 2D )を記述していきます。
今回は xib も使えるように OpenGL ESテンプレートから作成していきます!
②
まずはプロジェクトの作成
⦿ [XCode] → [新規プロジェクト]
[OpenGL Game] で作成
ストーリーボードはよく知らないのでチェック外す。
IOS6 では ViewController で全て初期化から描画までやっている模様!
.mを見てみると
(((( ;゚д゚)))) お・おう・・・
みたいな感じになったので、全部削除削除削除削除!
ViewController.m を ViewDidLoad のみにする!!
/** ViewController.m の中身 **/
#import "ViewController.h"
@implementation ViewController
そして新しく、
UIView クラスを継承した MainGLViewクラスを作成し、OpenGL ESの初期化をそこに記述します。
描画は全部 View に行われるので..
OpenGL ES も例外ではないです。
名前を MainGLView で作成....
ViewController.xib を開いて、
ViewController の View に...
MainGLView と設定。
そして次に MainGLViewでOpenGL ESの描画準備をします。
取り敢えず、QuartzCore.framework をプロジェクトに追加します。
これがないと CAEAGLLayer とやらを使用する時に
よくわからないエラーが出ます。 (゚Д゚)
CAEAGLLayer とは OpenGL ES専用のレイヤです。
レイヤとは描画先みたいな感じです。
OpenGL ES はこのレイヤを持っているUIView に 描画しないと 画面に現れてくれません。
というかエラーになります。
-----
UIViewは常にレイヤを持っています。
「UIViewに描画 = UIViewが持っているレイヤに描画」
CoreGraphicsでもなんでも結局は全てレイヤに描画されるわけです。
今回はOpenGL ES 専用のレイヤを使用します。
-----
なので、 MainGLView.m でこいつを使用するために関数を追加します。
上のほうで...
を記述。
これで自動的に MainGLViewは、
CAEAGLLayer が使用される事になりました。
※これを書かないと通常の レイヤが MainGLView に自動的にセットされます。
つぎに、ヘッダーに変数と関数を追加。
#import <UIKit/UIKit.h>
@interface MainGLView : UIView
{
/** OpenGL ESの描画設定を保持する物 **/
EAGLContext* mpGLContext;
/** フレームバッファとレンダバッファ **/
GLuint mFrameBuffer;
GLuint mColorBuffer; // カラーレンダバッファ
}
/**
* 描画準備
*/
- ( void ) BeginScene;
/**
* 描画終了
*/
- ( void ) EndScene;
@end
ヘッダーにEAGLContext という、
OpenGL ES の描画設定等を保存する入れ物を記述。
こいつを描画前に OpenGL に指定してやることで OpenGL はこいつの中にある設定情報を使い、
それにあった描画をするんです。
描画に必要なものが全て入る素晴らしい入れ物だと思っておきます(`・ω・´)
OpenGLを使うためにもまずはこのコンテキストを作成しなければなりません。
*****************************
ここからは
MainGLView.m の
//- (id)initWithFrame:(CGRect)frame
- ( id ) initWithCoder:(NSCoder *)aDecoder
{
self = [ super initWithCoder:aDecoder ];
}
に書いていきます。
ちなみにこの記事の一番下に全部記述したソース、あります。
なぜ initWithCoder に書き換えたのかというと、
xib で、ViewContollerに オリジナルのView を設定し、自動的にオリジナルViewを生成するようにした場合
そのViewの initWithFrame は呼び出されません。
なので 初期化をするためには initWithCoder にする必要がある。
*****************************
話を戻し、
OpenGL ES 用のContext ( 設定情報を保持する物 ) は
EAGLContext の initWithAPI 関数で作成できます。
[ [EAGLContext alloc] initWithAPI: /** 引数 **/ ];
"引数" には
が指定でき、
kEAGLRenderingAPIOpenGLES1
の方は固定機能を使用したOpenGL ES 1.1 を
kEAGLRenderingAPIOpenGLES2
の方は主に自分で機能を全て記述するタイプの OpenGL ES 2.0 を使用します。
2Dを使用する場合は OpenGL ES に必要な機能( 固定機能 )
を自動的に提供してくれる OpenGL 1.1 の方で十分です。
後2つの変数は フレームバッファと(カラー)レンダバッファです。
------
● フレームバッファ
レンダバッファを複数持ってくれる領域。
● レンダバッファ
描画に直接関係する領域。
------
バッファとは記憶領域的な感じだと思っています。
レンダ = 描画なので
描画した情報を保持してくれる領域 = レンダバッファ だと思います。
今回宣言しているレンダバッファは
画面のピクセル色情報が入る領域にします。 だから mColorBuffer という名前
他にもレンダバッファは、
3Dで奥行きを利用する時に使う
【ピクセルごとの Z座標 の値を持ってくれる深度レンダバッファ】などがあります。
レンダバッファはピクセルごとの情報を入れることから、
描画画面( iPhoneのデフォルトでは 横:320pix, 縦:480pix で十分 )と同じ大きさを取ります。
2Dでは基本色情報以外いらないので、
カラーレンダバッファのみ設定すればいいと思います。
で、
作成したカラーレンダバッファをフレームバッファという入れ物に格納します。
さらに、そのフレームバッファをコンテキストに格納します。
そしたら、、、
コンテキストをOpenGLにセットするだけで描画の準備が整います。
色以外にも奥行きとか様々なレンダバッファが作成できるので
纏め役としてフレームバッファがいる。
今回は色のみ。
フレームバッファとレンダバッファの作成と設定方法は良く似ています。
今回だと、
”1 つ" フレームバッファ と レンダバッファ を作成して
2番目の引数( 今回は、mFrameBuffer と mColorBuffer )に
"作成した領域の『識別子』” を渡す。
そして作成したフレームバッファとレンダバッファを
作成済みのコンテキストにバインド( 設定 )する。
で、コンテキストの中で レンダバッファをカラーレンダバッファとして
フレームバッファに設定します。
これは一度 フレームバッファとレンダバッファを コンテキストに格納してから設定します。
GL_COLOR_ATTACHMENT0 で、
カラーレンダバッファの0番目としてフレームバッファに登録しているわけです。
基本は GL_COLOR_ATTACHMENT0 のみで良い!
この関数を通ればもう大丈夫です( ゚д゚ )
しかし、カラーレンダバッファに描画した所で
画面に出てくるわけではありませんね。
iPhone では画面に色を出させるためには、画面に出てくるUIViewの
レイヤに描画しなければなりません。 上で作成したOpenGL ES用のレイヤに。
今回はOpenGL ES初期化処理をView( MainGLView )に書いているので、
自分自身のレイヤに描画するわけですね。
そしてMainGLViewはVIewControllerに xib でセットされているので
これでiPhoneの画面に レイヤの内容 = 描画物 が現れる仕掛けになっている。
なので、
カラーレンダバッファに描画した内容を
描画するレイヤ(今回は自分) にコピーしてあげます。
まずはレイヤをレンダバッファに設定。
設定後、
OpenGLESの様々な描画関数でレンダバッファに描画して、
"presentRenderbuffer" という関数を呼び出すことで、
【レンダバッファの中身が、レンダバッファに設定したレイヤにコピーされる。】
= 画面に出てくる。 というわけです。
ですから
レンダバッファの大きさは画面(レイヤ)の大きさと一緒にしとかないといけません。
これによりごっそりとそのままコピーできます。
描画の前に注意点。
ゲームは常にループしています。
ループごとに次々とカラーレンダバッファに描画していき、レイヤにぽいぽいコピーすると
前回の描画情報と今回の描画情報が入ったままレイヤにコピーされるので
画面に前回の描画分までもが出てくるという、嫌な感じになります。
毎回、ループのはじめで
レンダバッファの中身を綺麗サッパリ消してやります。
という感じになります。
これでカラーレンダバッファの中身はつねに清潔に保たれます。
初期化の最後に OpenGL ES を 2Dで簡単に使用できるような設定をします。
そのための関数が
これになります。
これは座標系を変更する OpenGL ES 1.1 専用の関数です。
OpenGL ES は3Dを扱う為に、座標系が特殊です。
左上が ( -1.0, 1.0 ) で、 右下の座標が ( 1.0, -1.0 ) となります。
中心に ( 0.0, 0.0 ) が来るのは3Dではとても扱いやすいのですが、
2D では煩わしいこと言語道断です(# ゚Д゚)
なので、 glOrthof 関数で
こんな風に
左上が ( 0.0, 0.0 )、 右下が ( 320.0, 480.0 ) になるようにすれば
一々 -1.0 ~ 1.0 の間に直す手間が省けてとても使いやすくなります。
最後に
glViewport( 0, 0, 320, 480 );
というもので どこからどこまでの範囲に描画するか決定します。
今回はあいぽんの画面全体なので 320, 480 です。
初期化はこれで終わりです。 + その他もろもろは適当に覚えておいたら良い。
その一連の流れを記述した MainGLView.m のコードが ↓
これで MainGLView に描画の準備が整いました。
BeginScene関数呼び出し と EndScene関数呼び出し の間 に OpenGL の描画処理を書くと描画されます。
実際に使ってみましょう。
・・ なんか文字数の制限で書けなくなったので、、、
(URL)続く!!!
真面目に更新して行こうとぉ・・・・、、思います!
iPhoneでアプリを作成する時に画像の描画をしますが、
一度に画面に出す画像の枚数が多くなってくると、思った速度が出ず
に悩んだりすることが出てきます。(多分)
そういう時にGPUをフルに使ってくれる OpenGL ES を使用するのですが、
「 むずい 」 「 めんどくさい 」 「 もういやだ!」
の 3M が襲いかかってきます。
OpenGL ES の敷居が高い!!(半年前のわたくし)
と思われがちですが、実際そうでもないです。 ( 2Dの場合は )
一個ずつ見ていくと初めての方でも意外に簡単だったりするものなので、
時間をかけてゆるりと初期化部分を見ていくことにします
①
現在 IOS6 では 初期化がすこぶる簡単になったそうなので、
今更こんな旧式の初期化は必要ないかと思いますが、
僕は IOS4 時代の初期化方法を調べた時、OpenGL ESが内部で何を行なっているか「なるへそ」と理解し、
感動した気持ちで胸が昂ぶり震えたので多用しています。
なので、旧式のOpenGL ES の初期化方法( 2D )を記述していきます。
今回は xib も使えるように OpenGL ESテンプレートから作成していきます!
②
まずはプロジェクトの作成
⦿ [XCode] → [新規プロジェクト]
[OpenGL Game] で作成
ストーリーボードはよく知らないのでチェック外す。
IOS6 では ViewController で全て初期化から描画までやっている模様!
ViewController.h
では、まず継承元を UIViewController に変更
これで このViewController で勝手にOpenGL ESの初期化をさせない(ΦωΦ)フフフ…
.mを見てみると
(((( ;゚д゚)))) お・おう・・・
みたいな感じになったので、全部削除削除削除削除!
ViewController.m を ViewDidLoad のみにする!!
/** ViewController.m の中身 **/
#import "ViewController.h"
@implementation ViewController
/**
* MainGLView が呼び出された。
*/
- (void)viewDidLoad
{
[super viewDidLoad];
}
@end
そして新しく、
UIView クラスを継承した MainGLViewクラスを作成し、OpenGL ESの初期化をそこに記述します。
描画は全部 View に行われるので..
OpenGL ES も例外ではないです。
名前を MainGLView で作成....
ViewController.xib を開いて、
ViewController の View に...
MainGLView と設定。
これで 実行時に呼び出されるViewController の 初期View が MainGLView に設定され、
勝手に MainGLView が呼び出され、ViewControllerに設定されるようになりました。
そして次に MainGLViewでOpenGL ESの描画準備をします。
取り敢えず、QuartzCore.framework をプロジェクトに追加します。
これがないと CAEAGLLayer とやらを使用する時に
よくわからないエラーが出ます。 (゚Д゚)
CAEAGLLayer とは OpenGL ES専用のレイヤです。
レイヤとは描画先みたいな感じです。
OpenGL ES はこのレイヤを持っているUIView に 描画しないと 画面に現れてくれません。
というかエラーになります。
-----
UIViewは常にレイヤを持っています。
「UIViewに描画 = UIViewが持っているレイヤに描画」
CoreGraphicsでもなんでも結局は全てレイヤに描画されるわけです。
今回はOpenGL ES 専用のレイヤを使用します。
-----
なので、 MainGLView.m でこいつを使用するために関数を追加します。
上のほうで...
/**
* この関数を書くことで OpenGL ESを描画できるレイヤーを自動的にセットする
*/
+ ( Class )layerClass
{
return [ CAEAGLLayer class ];
}
を記述。
これで自動的に MainGLViewは、
CAEAGLLayer が使用される事になりました。
※これを書かないと通常の レイヤが MainGLView に自動的にセットされます。
つぎに、ヘッダーに変数と関数を追加。
#import <UIKit/UIKit.h>
@interface MainGLView : UIView
{
/** OpenGL ESの描画設定を保持する物 **/
EAGLContext* mpGLContext;
/** フレームバッファとレンダバッファ **/
GLuint mFrameBuffer;
GLuint mColorBuffer; // カラーレンダバッファ
}
/**
* 描画準備
*/
- ( void ) BeginScene;
/**
* 描画終了
*/
- ( void ) EndScene;
@end
ヘッダーにEAGLContext という、
OpenGL ES の描画設定等を保存する入れ物を記述。
こいつを描画前に OpenGL に指定してやることで OpenGL はこいつの中にある設定情報を使い、
それにあった描画をするんです。
描画に必要なものが全て入る素晴らしい入れ物だと思っておきます(`・ω・´)
OpenGLを使うためにもまずはこのコンテキストを作成しなければなりません。
*****************************
ここからは
MainGLView.m の
//- (id)initWithFrame:(CGRect)frame
- ( id ) initWithCoder:(NSCoder *)aDecoder
{
self = [ super initWithCoder:aDecoder ];
}
に書いていきます。
ちなみにこの記事の一番下に全部記述したソース、あります。
なぜ initWithCoder に書き換えたのかというと、
xib で、ViewContollerに オリジナルのView を設定し、自動的にオリジナルViewを生成するようにした場合
そのViewの initWithFrame は呼び出されません。
なので 初期化をするためには initWithCoder にする必要がある。
*****************************
話を戻し、
OpenGL ES 用のContext ( 設定情報を保持する物 ) は
EAGLContext の initWithAPI 関数で作成できます。
[ [EAGLContext alloc] initWithAPI: /** 引数 **/ ];
"引数" には
● kEAGLRenderingAPIOpenGLES1
● kEAGLRenderingAPIOpenGLES2
● kEAGLRenderingAPIOpenGLES2
が指定でき、
kEAGLRenderingAPIOpenGLES1
の方は固定機能を使用したOpenGL ES 1.1 を
kEAGLRenderingAPIOpenGLES2
の方は主に自分で機能を全て記述するタイプの OpenGL ES 2.0 を使用します。
2Dを使用する場合は OpenGL ES に必要な機能( 固定機能 )
を自動的に提供してくれる OpenGL 1.1 の方で十分です。
3Dでも固定機能で十分な場合がありますが、上手く利用したい場合は 2.0 の方を採用するといいと思います。
こういう感じで作成~
/** 全てのプラットフォームに対応させるため今回はOpenGL ES 1.1を採用する **/
mpGLContext = [ [EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 ];
mpGLContext = [ [EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 ];
後2つの変数は フレームバッファと(カラー)レンダバッファです。
------
● フレームバッファ
レンダバッファを複数持ってくれる領域。
● レンダバッファ
描画に直接関係する領域。
------
バッファとは記憶領域的な感じだと思っています。
レンダ = 描画なので
描画した情報を保持してくれる領域 = レンダバッファ だと思います。
今回宣言しているレンダバッファは
画面のピクセル色情報が入る領域にします。 だから mColorBuffer という名前
他にもレンダバッファは、
3Dで奥行きを利用する時に使う
【ピクセルごとの Z座標 の値を持ってくれる深度レンダバッファ】などがあります。
レンダバッファはピクセルごとの情報を入れることから、
描画画面( iPhoneのデフォルトでは 横:320pix, 縦:480pix で十分 )と同じ大きさを取ります。
2Dでは基本色情報以外いらないので、
カラーレンダバッファのみ設定すればいいと思います。
で、
作成したカラーレンダバッファをフレームバッファという入れ物に格納します。
さらに、そのフレームバッファをコンテキストに格納します。
そしたら、、、
コンテキストをOpenGLにセットするだけで描画の準備が整います。
色以外にも奥行きとか様々なレンダバッファが作成できるので
纏め役としてフレームバッファがいる。
今回は色のみ。
フレームバッファとレンダバッファの作成と設定方法は良く似ています。
glGenFramebuffers( 1, &mFrameBuffer ); // フレームバッファの作成
glGenRenderbuffers( 1, &mColorBuffer ); // レンダバッファの作成
glGenRenderbuffers( 1, &mColorBuffer ); // レンダバッファの作成
今回だと、
”1 つ" フレームバッファ と レンダバッファ を作成して
2番目の引数( 今回は、mFrameBuffer と mColorBuffer )に
"作成した領域の『識別子』” を渡す。
という感じです。
GLuint型( ただの4バイト変数 )なので、 mFameBuffer, mColorBuffer に領域が直接入っているわけではない。
領域を示す識別子が入る。
そして作成したフレームバッファとレンダバッファを
作成済みのコンテキストにバインド( 設定 )する。
glBindFramebuffer( GL_FRAMEBUFFER, mFrameBuffer );
glBindRenderbuffer( GL_RENDERBUFFER, mColorBuffer );
glBindRenderbuffer( GL_RENDERBUFFER, mColorBuffer );
で、コンテキストの中で レンダバッファをカラーレンダバッファとして
フレームバッファに設定します。
これは一度 フレームバッファとレンダバッファを コンテキストに格納してから設定します。
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mColorBuffer );
GL_COLOR_ATTACHMENT0 で、
カラーレンダバッファの0番目としてフレームバッファに登録しているわけです。
基本は GL_COLOR_ATTACHMENT0 のみで良い!
これで OpenGL ES で描画を行うと
コンテキストに設定されているフレームバッファのカラーレンダバッファ 、
つまり mColorBuffer の指定したバッファ(領域)に描画されることになります。
そしてフレームバッファが正しく使用出来る状態になったかどうかチェックする
glCheckFramebufferStatus 関数があります。
/** フレームバッファが正しく設定されたかチェックする **/
if ( glCheckFramebufferStatus( GL_FRAMEBUFFER ) != GL_FRAMEBUFFER_COMPLETE )
{
/** 正しく設定されていない! **/
}
if ( glCheckFramebufferStatus( GL_FRAMEBUFFER ) != GL_FRAMEBUFFER_COMPLETE )
{
/** 正しく設定されていない! **/
}
この関数を通ればもう大丈夫です( ゚д゚ )
しかし、カラーレンダバッファに描画した所で
画面に出てくるわけではありませんね。
iPhone では画面に色を出させるためには、画面に出てくるUIViewの
レイヤに描画しなければなりません。 上で作成したOpenGL ES用のレイヤに。
今回はOpenGL ES初期化処理をView( MainGLView )に書いているので、
自分自身のレイヤに描画するわけですね。
そしてMainGLViewはVIewControllerに xib でセットされているので
これでiPhoneの画面に レイヤの内容 = 描画物 が現れる仕掛けになっている。
なので、
カラーレンダバッファに描画した内容を
描画するレイヤ(今回は自分) にコピーしてあげます。
まずはレイヤをレンダバッファに設定。
/** これでレンダバッファの内容を自分のレイヤーに移すよう設定 **/
[ mpGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:( CAEAGLLayer* )self.layer ];
[ mpGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:( CAEAGLLayer* )self.layer ];
設定後、
OpenGLESの様々な描画関数でレンダバッファに描画して、
"presentRenderbuffer" という関数を呼び出すことで、
【レンダバッファの中身が、レンダバッファに設定したレイヤにコピーされる。】
= 画面に出てくる。 というわけです。
ですから
レンダバッファの大きさは画面(レイヤ)の大きさと一緒にしとかないといけません。
これによりごっそりとそのままコピーできます。
描画の前に注意点。
ゲームは常にループしています。
ループごとに次々とカラーレンダバッファに描画していき、レイヤにぽいぽいコピーすると
前回の描画情報と今回の描画情報が入ったままレイヤにコピーされるので
画面に前回の描画分までもが出てくるという、嫌な感じになります。
毎回、ループのはじめで
レンダバッファの中身を綺麗サッパリ消してやります。
/** 指定した色でクリアするよう設定 **/
glClearColor( 0.8f, 0.85f, 0.9f, 1.0f );
/** 消す対象はカラーバッファ **/
glClear( GL_COLOR_BUFFER_BIT );
------- 描画処理 ---------
// 描画終了後 ↓ を呼び出す
/** この関数でコンテキストが持っているレンダバッファの内容を設定されたレイヤにコピーする **/
[ mpGLContext presentRenderbuffer:GL_RENDERBUFFER ];
glClearColor( 0.8f, 0.85f, 0.9f, 1.0f );
/** 消す対象はカラーバッファ **/
glClear( GL_COLOR_BUFFER_BIT );
------- 描画処理 ---------
// 描画終了後 ↓ を呼び出す
/** この関数でコンテキストが持っているレンダバッファの内容を設定されたレイヤにコピーする **/
[ mpGLContext presentRenderbuffer:GL_RENDERBUFFER ];
という感じになります。
これでカラーレンダバッファの中身はつねに清潔に保たれます。
初期化の最後に OpenGL ES を 2Dで簡単に使用できるような設定をします。
そのための関数が
/** X を 0.0f ~ 320.0 に、 Y を 0.0 ~ 480.0f にする **/
// 左X, 右X, 下Y, 上Y, 手前Z, 奥Z
glOrthof( 0.0f, 320.0f, 480.0f, 0.0f, 0.5f, -0.5f );
// 左X, 右X, 下Y, 上Y, 手前Z, 奥Z
glOrthof( 0.0f, 320.0f, 480.0f, 0.0f, 0.5f, -0.5f );
これになります。
これは座標系を変更する OpenGL ES 1.1 専用の関数です。
OpenGL ES は3Dを扱う為に、座標系が特殊です。
左上が ( -1.0, 1.0 ) で、 右下の座標が ( 1.0, -1.0 ) となります。
中心に ( 0.0, 0.0 ) が来るのは3Dではとても扱いやすいのですが、
2D では煩わしいこと言語道断です(# ゚Д゚)
なので、 glOrthof 関数で
こんな風に
左上が ( 0.0, 0.0 )、 右下が ( 320.0, 480.0 ) になるようにすれば
一々 -1.0 ~ 1.0 の間に直す手間が省けてとても使いやすくなります。
最後に
glViewport( 0, 0, 320, 480 );
というもので どこからどこまでの範囲に描画するか決定します。
今回はあいぽんの画面全体なので 320, 480 です。
初期化はこれで終わりです。 + その他もろもろは適当に覚えておいたら良い。
その一連の流れを記述した MainGLView.m のコードが ↓
#import "MainGLView.h"
#import <GLKit/GLKit.h>
#import <GLKit/GLKit.h>
#import <QuartzCore/QuartzCore.h>
@implementation MainGLView
/**
* このクラスメソッドをオーバーライドすることで OpenGL ESを描画できるレイヤーをセットする
*/
+ ( Class )layerClass
{
return [ CAEAGLLayer class ];
}
//- (id)initWithFrame:(CGRect)frame ← xibではこれは呼び出されない
- ( id ) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
/** 設定されたレイヤの取得 **/
CAEAGLLayer* pGLLayer = ( CAEAGLLayer* )self.layer;
// 不透明にすることで処理速度が上がる
pGLLayer.opaque = YES;
/** 描画の設定を行う **/
// 辞書登録をする。
// 順番として 値 → キー
pGLLayer.drawableProperties = [ NSDictionary dictionaryWithObjectsAndKeys:
/** 描画後レンダバッファの内容を保持しない。 **/
[ NSNumber numberWithBool:FALSE ],
kEAGLDrawablePropertyRetainedBacking,
/** カラーレンダバッファの1ピクセルあたりRGBAを8bitずつ保持する **/
kEAGLColorFormatRGBA8,
kEAGLDrawablePropertyColorFormat,
/** 終了 **/
nil ];
/** 全てのプラットフォームに対応させるため今回はOpenGL ES 1.1を採用する **/
mpGLContext = [ [EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1 ];
/** 現在のコンテキストにレンダリングコンテキストを設定する **/
[ EAGLContext setCurrentContext:mpGLContext ];
/** フレームバッファを作成する **/
// Gen で作成 → Bind で現在のコンテキストに格納。 の流れ
glGenFramebuffers( 1, &mFrameBuffer ); // かぶらない識別子を渡す
glBindFramebuffer( GL_FRAMEBUFFER, mFrameBuffer ); // コンテキストに与えられた識別子をもつフレームバッファを作成
/** カラーレンダバッファを作成する **/
glGenRenderbuffers( 1, &mColorBuffer );
glBindRenderbuffer( GL_RENDERBUFFER, mColorBuffer );
// 先ほどのレンダバッファオブジェクトに描画するために必要なストレージを割り当てる。
// fromDrawable : レンダバッファにバインドするストレージ
// ストレージをレイヤに割り当てることで、バッファに書き込んだらレイヤに書き込まれる!
[ mpGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:( CAEAGLLayer* )self.layer ];
// フレームバッファとレンダバッファを結びつける
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mColorBuffer );
/** フレームバッファが正しく設定されたかチェックする **/
if ( glCheckFramebufferStatus( GL_FRAMEBUFFER ) != GL_FRAMEBUFFER_COMPLETE )
NSLog( @"フレームバッファが正しくありません! %x", glCheckFramebufferStatus( GL_FRAMEBUFFER ) );
/** X を 0.0f ~ 320.0 に、 Y を 0.0 ~ 480.0f にする **/
// 左X, 右X, 下Y, 上Y, 手前Z, 奥Z
glOrthof( 0.0f, 320.0f, 480.0f, 0.0f, 0.5f, -0.5f );
/** ビューポートの作成 **/
glViewport( 0, 0, 320, 480 );
}
/** ビューポートの作成 **/
glViewport( 0, 0, 320, 480 );
}
return self;
}
/**
* 描画準備
*/
- ( void ) BeginScene
{
/** 画面を指定した色でクリアする **/
glClearColor( 0.8f, 0.85f, 0.9f, 1.0f );
/** クリアする対象のバッファを指定 **/
// 色を指定
glClear( GL_COLOR_BUFFER_BIT );
}
/**
* 描画終了
*/
- ( void ) EndScene
{
// 画面上( ビューの持つレイヤ )にレンダバッファのコンテンツを表示する
[ mpGLContext presentRenderbuffer:GL_RENDERBUFFER ];
}
/**
* 終了
*/
- ( void )dealloc
{
glDeleteFramebuffers( 1, &mFrameBuffer );
glDeleteRenderbuffers( 1, &mColorBuffer );
}
@end
BeginScene関数呼び出し と EndScene関数呼び出し の間 に OpenGL の描画処理を書くと描画されます。
実際に使ってみましょう。
・・ なんか文字数の制限で書けなくなったので、、、
(URL)続く!!!
/V\
/◎;;;,;,,,,ヽ
_ ム::::(,,゚Д゚)::|
ヽツ.(ノ:::::::::.:::::.:..|)
ヾソ:::::::::::::::::.:ノ
` ー U'"U'
/◎;;;,;,,,,ヽ
_ ム::::(,,゚Д゚)::|
ヽツ.(ノ:::::::::.:::::.:..|)
ヾソ:::::::::::::::::.:ノ
` ー U'"U'