Archive for the ‘openGL’ Category

[obj-c, openGL] GLKitについて

メリークリスマス!!

iOS Advent calendarに参加してまして、24日クリスマスイブの日の記事になります。
いままで23個の記事が出てきていますが、自分が興味があった & 被らなかった のでネタは GLKit にしました。
勉強しながらなので薄い内容ですが、ご了承ください。

openGLを使って遊んだりしてたけど、iPhoneでopenGLいじろうとしたらopenGL ES 2.0でなんかいろいろ違うじゃーんという思いを胸に、
勉強していきたいと思います。

記事の流れはこんな感じです。

  • ・openGL と openGL ES 2.0
  • ・GLKitとは
  • ・GLKitのテンプレさわってみる

openGL と openGL ES 2.0

まずはopenGLとopenGL ES 2.0の違い

  • openGL ES 2.0では固定機能シェーダを完全に廃止
  •    glVertexPointer, glNormalPointer などの頂点系の削除
  •    glPushMatrix, glPopMatrix などのマトリックス系の削除
  •    glLight〜 などのライティング系の削除


  • プログラマブルシェーダのみの実装。
  •    バーテックスシェーダ, フラグメントシェーダ などのシェーダを使う
などなど。ここ を参考に。

今までopenGLの勉強したり遊んだりする場合は、固定機能シェーダを使ってました。
GLSLもすこし勉強しているものの、まだ全然使えていないので固定機能シェーダが使えずプログラマブルシェーダだけでやっていく
openGL ES 2.0 は僕には敷居が高いです。。

そんなとき、GLKit の出番!ということですね。
shader書かかず、openGL ES 2.0でopenGL的なことができるクラスが用意されているみたいです。


GLKit について

iOS 5で追加されたopenGLのフレームワークで、openGL ES 2.0を使いやすくしてくれます。

リファレンスより(google翻訳使いました)

openGL ES 2.0 アプリケーションを作成するのに必要な労力や、
既存の openGL ES 1.1 アプリケーションを openGL ES 2.0 に移植するための労力を減らすためのライブラリを提供します。

主な機能
  • Texture loading : テクスチャーの扱いを簡単にしてくれる
  • Math libraries : 最適化されたベクトル、行列の関数が用意されている
  • Views and View Controllers : openGL ESのレンダリング、ループの実装を提供してくれる
  • Effects : 必要なシェーダの実装をやってくれる
Effects機能のGLKBaseEffectでライティングやマトリックス系の処理やってくれます。
他にもopenGL的な書き方ができるのとGLU系の関数と似たものが用意されていたりします。
こちら で詳しく説明されているので、ここにぐわーと書いたの読むより、そちらを読んだ方が深く理解できるかと思います。


GLKitのテンプレさわってみる

とりあえず最低限の使い方を理解したいので、テンプレート触ってみます。
GLKitの機能を使っているものと、shaderを使っているものの2つ分記述してあるみたいなので、GLKitの部分だけを見ていきます。

最初は立方体が2つぐるぐる回ってますが、シンプルにしていって最終的にはこんな感じに。

glkit_sample

// - (void)viewDidLoad

    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];


初期化と、指定したバージョンの OpenGL ES レンダリングAPIを割り当て。


// - (void)viewDidLoad

    GLKView * view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;


GLKitの準備。


// - (void)setupGL

    [EAGLContext setCurrentContext:self.context];
    
    self.effect = [[GLKBaseEffect alloc] init];
    self.effect.light0.enabled = GL_TRUE;
    self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 0.4f, 0.4f, 1.0f);


最初に現在のレンダリングスレッドをセット。

次にGLKBaseEffectクラスのeffect変数にライティングを設定しています。
openGLでは8つの光源が設定できましたが、GLKBaseEffect.light* は0, 1, 2の3つしかないっぽいです。
ていうかopenGL ESはもともと3つしかないのかな?
エフェクトの初期化を抜けば、2行でライティングの設定ができて楽です。

その後はVBOの設定をしているみたいです。


// - (void)tearDownGL

    [EAGLContext setCurrentContext:self.context];
    
    glDeleteBuffers(1, &_vertexBuffer);
    self.effect = nil;


viewDidUnloadではtearDownGL関数を呼んでいます。
後始末。


// - (void)update

    /**
     * PROJECTION
     */
    float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0f, 100.0f);
    self.effect.transform.projectionMatrix = projectionMatrix;
    
    /**
     * MODEL VIEW
     */
    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -3.0f);
    modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 1.0f, 1.0f, 1.0f);
    self.effect.transform.modelviewMatrix = modelViewMatrix;



更新用のデリゲートメソッド
本来はglkViewControllerUpdateだけど、 GLKViewControllerのサブクラスだからupdateを呼べばいい?(たぶん)

まずはopenGLでいうところの glMatrixMode(GL_PROJECTION); 的な部分の記述。
GLKMatrix4MakePerspectiveではgluPerspectiveとほぼほぼ同じようにかけます。GLU系が使えないけど代替の機能があるので助かります。
最後にeffect.transform.projectionMatrixに代入。

次にopenGLでいうところの glMatrixMode(GL_MODELVIEW); 的な部分の記述。
GLKMatrix4MakeTranslationでマトリックス作りつつtranslationの設定。glTranslatedてきな感じ。
あとは必要な設定をしてeffect.transform.modelviewMatrixに代入。
glTranslated, glRotate, glScaleっぽい設定ができます。

テンプレではGLKMatrix4Multiplyを使って2つのマトリックを掛け合わせたりしてるみたいですが、
とりあえずはシンプルに理解したいので、そこはカット。

最後にテンプレではアニメーション用の_rotationの値を更新してます。


//- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    [self.effect prepareToDraw];
    glDrawArrays(GL_TRIANGLES, 0, 36);


描画用のデリゲートメソッド
prepareToDrawメソッドで エフェクト使うよ というのを定義して、
その後描画してます。


まとめ

いまはopenGLにすごく興味があるので、GLKitを勉強してみました。

GLKitがあればシェーダの知識がなくても使うことができて便利なので、
アプリにちょっとだけopenGL使いたいってなったときにはこれから使っていけそうです。
ただ個人的にはやっぱりシェーダーをしっかり覚えていきたいので、がっつり使って何か作るという機会はなさそうです。
ゲームっぽいの作ろう!ってなってもきっとcocos2d使うと思いますし。

クリスマスが爆発する何かを作る予定でしたが、時間がなくて断念。
勉強しながらの薄い内容で申し訳なかったですが、みなさんよいクリスマスイブを〜!!

間違いなどのご指摘あれば @_azzip まで連絡ください。


参考

http://developer.apple.com/library/ios/#documentation/GLkit/Reference/GLKit_Collection/_index.html
http://nantekottai.com/2011/10/13/opengl-game-template/
http://nantekottai.com/2011/10/25/glkit-basics/
http://d.hatena.ne.jp/nakamura001/20111117/1321545530
http://monsho.blog63.fc2.com/blog-category-5.html
http://d.hatena.ne.jp/ntaku/20090610/1244619913
http://www.asahi-net.or.jp/~yw3t-trns/opengl/opengles/index.htm





[openGL, GLSL] openGL+GLSLのメモ #2 座標系

openGLとかGLSLやっていくうえで座標系がしっかり理解できてないとこの先理解できないので、
基礎的なことだけどちゃんとメモ。

座標系と変換の流れ

1. オブジェクト座標系(モデリング座標、ローカル座標)
オブジェクトの頂点や法線を表す座標系

  •     ▼ モデリング変換 : オブジェクト座標系をワールド座標系に変換
2. ワールド座標系(グローバル座標系)
空間中のオブジェクトの位置を示す座標系
  •     ▼ 視野変換(ビューイング変換) : ワールド座標系から視点座標系への変換
3. 視点座標系(眼点座標系)
空間を視点(カメラ)から見た空間へ変換した座標系。
  •     ▼ 射影変換 : 視点座標系からクリップ座標系への変換(オブジェクトの奥行き情報を保持する変換)
4. クリップ座標系
視点からの近平面と遠平面をクリッピングする座標系(たぶん)
  •     ▼ 遠近除算 : 遠近除算(正規化)処理をすることで、クリップ座標系から正規化デバイス座標系になる
5. 正規化デバイス座標系
クリップ座標系の座標 x, y, z 成分を w で割った座標系
  •     ▼ ビューポート変換 : 正規化デバイス座標系からウインドウ座標系への変換
6. ウインドウ座標系
表示画面に対応するピクセル単位の座標系




以下は実際のopenGLでの処理。流れは逆からになる。

ビューポート変換 5 → 6

正規化デバイス座標系からウインドウ座標系への変換
ウインドウに設定される実際の描画領域の設定
通常は表示ウインドウとビューポートのサイズを一致させて作る

void glViewport(GLint x , GLint y , GLsizei width , GLsizei height);



射影変換 3 → 4, 5

視点座標系からクリップ座標系に変換
投影の設定

glMatrixMode( GL_PROJECTION );
glLoadIdentity();


射影行列を使うことを宣言してから、変換を行う

・透視投影の場合
void gluPerspective(
	GLdouble fovy , GLdouble aspect ,
	GLdouble zNear , GLdouble zFar
);


aspectをビューポート変換で設定した width / height に設定することで
図形の長さの比が保たれるようになる

・正射影の場合
void glOrtho(
	GLdouble left , GLdouble right ,
	GLdouble bottom , GLdouble top , 
	GLdouble near , GLdouble far      
);



視野変換 2 → 3

ワールド座標系から視点座標系への変換
視点の設定と中心点の設定を行う

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();


モデルビュー行列を使うことを宣言してから、変換を行う
void gluLookAt(GLdouble ex, GLdouble ey, GLdouble ez, 
			 GLdouble cx, GLdouble cy, GLdouble cz, 
			 GLdouble ux, GLdouble uy, GLdouble uz)
//例)
gluLookAt(3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);


ex, ey, ez : 視点(カメラ)の位置
cx, cy, cz : シーンの中心点
ux, uy, uz : 視体積の上方部分( 通常は 0.0, 1.0, 0.0 でおっけ)


モデリング変換 1 → 2

オブジェクト座標系をワールド座標系に変換
下記の関数を利用して変換することを「アフィン変換(モデリング変換)」という

glScale*(sx, sy, sz);
glRotate*(angle, ax, ay, az);
glTranslate*(tx, ty, tz);



オブジェクトの描画

実際に表示させるオブジェクトを描画する



参考

OpenGL+GLSLによる画像処理プログラミング―「OpenGL」と「シェーダ言語」で「レタッチ・ソフト」の仕組みを知る! (I・O BOOKS)
OpenGLの座標系





[openGL, GLSL] openGL+GLSLのメモ #1

GLSL hello world シェーダーむずいですね。とりあえずは基礎からしっかりとな感じで頑張ってます。



OpenGL+GLSLによる画像処理プログラミング
この本とwebを見ながらGLSLの勉強したメモ。 まだ全部読んでないしよくわかってないけど頭の整理もかねて。

シェーダの種類

  • ・バーテックスシェーダ(頂点シェーダ)
  • ・フラグメントシェーダ(ピクセルシェーダ)

バーテックスシェーダ(頂点シェーダ)
頂点データを扱う。
“位置・色・テクスチャ” とかの頂点の属性だけを参照・変更できる。
バーテックスシェーダで計算された頂点は、ジオメトリシェーダかフラグメントシェーダに渡される。

フラグメントシェーダ(ピクセルシェーダ)
各ピクセルに影響し、テクスチャを参照することで “バンプマッピング・フォグ・シャドウ・ブルーム” とかのエフェクトをレンダリング結果に適用させる。
wiki見るとこんな感じらしい。
とりあえずは、バーテックスシェーダで頂点情報を計算して、フラグメントシェーダでエフェクトかけて、openGLに渡す
っていう流れでいいんですかね。


次はシェーダープログラムのほうのメモ。

shader.frag と shader.vert

参考にさせてもらったサイトのバーテックスシェーダとフラグメントシェーダのソースをほんーーのちょっとイジったやつ。

//shader.vert

uniform int a; //openGLと値のやりとり用
void main(void)
{
    //transform 
	gl_Position = ftransform();
	
    // normal color 
	gl_FrontColor.rgb = 0.5 * gl_Normal.xyz + 0.5;
	gl_FrontColor.a = float(a) * 0.01;
}


//shader.frag

void main (void)
{
	gl_FragColor = gl_Color;    
}


shader.vertのgl_FrontColorの値がshader.fragのgl_Colorに渡されて、
shader.fragのgl_FragColorの値がopenGL側に適用される感じ?
次あたりここら辺はまた詳しく勉強してメモしたいです。


openGLとGLSLでのやりとり

GLSLを使うためのお決まり処理の流れは、参考サイトに書かれているものによると、

  • 1. バーテックスシェーダとフラグメントシェーダのシェーダオブジェクトを作成 – glCreateShader();
  • 2. 作成したそれぞれのシェーダオブジェクトに対してソースプログラムを読み込む – glShaderSource();
  • 3. 読み込んだソースプログラムをコンパイル – glCompileShader();
  • 4. プログラムオブジェクトを作成 – glCreateProgram();
  • 5. プログラムオブジェクトに対してシェーダオブジェクトを登録 – glAttachShader();
  • 6. シェーダプログラムをリンク – glLinkProgram();
  • 7. シェーダプログラムを適用 – glUseProgram()
こんな流れらしい。 コピペしましたすいません。
ここは覚えたほうがいいんだろうけど、クラス化しておけば触れずにすむところではあるので、ちょっとスルーで。
とりあえず、この本のサンプルのGLSLのお決まり処理クラスをちょっと変えて自分の使いやすいようにして使わせてもらいます。


以下はopenGLとGLSLで値のやりとりの部分のメモ。
//main.cpp

//シェーダーオブジェクト
GLuint shader;

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    
    glUseProgram(shader); //シェーダーの適用

    GLint a = 80; //openGLとシェーダーでやりとりする変数
    GLint _loc01 = glGetUniformLocation(shader, "a");
    glUniform1i(_loc01, a);
    
    GLfloat vertex[][2]=
    {
        {10,10},
        {100,10},
        {10,100},
        {100,100}
    };
    glVertexPointer(2, GL_FLOAT, 0, vertex);    
    glEnableClientState(GL_VERTEX_ARRAY);    
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
    glUseProgram(0);  //シェーダーの適用の終了
    
    glFlush();
}


大事なところだけで抜粋。initとかの関数は無視。

//main.cpp

glUseProgram(shader);
/**
 *この部分で描画処理
 */
glUseProgram(0);


ここの描画処理の中に書かれたものにシェーダーが適用される。
上のソースでいうとglDrawArraysで書いた四角形にシェーダーが適用されている。

//main.cpp

GLint a = 80;
GLint _loc01 = glGetUniformLocation(shader, "a"); //値を渡すための準備
glUniform1i(_loc01, a); //値を渡す


openGLとシェーダーの値のやりとりの部分。
glGetUniformLocation : シェーダプログラムに値を渡すため、変数のインデックスを取得する。
glUniform1i : openGLからシェーダプログラムに渡す。
こんな関数を使えばいいらしい。
あらかじめシェーダプログラム側に変数を用意しておいて、それのインデックスを取得、それを使って値をシェーダプログラムに渡す流れ。

なんとなく、openGLとGLSL使うときの基礎的なメモはこんな感じで、ちょっとだけ苦手意識は消えた気が。気だけ。少しだけ。
これからは時間みてもうちょっとシェーダプログラムとかopenGLとGLSLで値のやりとりの部分とか、サクッとコピペで終わったGLSLのお決まり処理の部分とかやってきます!





[openGL , Xcode] Xcode4でglpngを使って画像を読み込むときのあれこれ

glpng.frameworkの作り方は下記のサイトを参考にさせてもらいました。
http://me-mo-me-mo.blogspot.com/2009/12/mac-glpng.html

でこれを普通に

#include <glpng/glpng.h>

GLuint texture[1];
pngInfo info;
texture[0] = pngBind ("texture.png", PNG_NOMIPMAP, PNG_ALPHA, &info, GL_CLAMP, GL_NEAREST, GL_NEAREST);
if(texture[0] == 0)
{
    printf("image not loaded");
}


で読み込んであげてテクスチャを貼りつけてあげればいいと思ったんですがなぜか画像読み込みの時にエラーがでてしまいい、、
パスが間違っているんだろうなと思いあっちやこっちやいろいろ画像置いて試したんですが、うまくいかず、、、


ぐぐってもほしい情報が手に入らなかったので、さらにゴニョゴニョいろいろ試した結果、やっとできたので忘れないようにメモ!

1) プロジェクト名のファイルをクリック
2) 出てくるTARGETSをクリック
3) タブのBuild Phasesをクリック
4) ライブラリとか読みこんであるやつの下の Copy Files ってやつを選択して、

glpng 上の画像のように読み込ませたいテクスチャの画像を追加。
そういえばXcode3のときはresourceフォルダに入れてたなーと思いつつこれがresourceフォルダの代わりなんだなてきな解釈でいいやと思いました。
※ Copy only when installing のチェックをはずさなかったらエラーがでたけど良く分からん。。

これでビルドしたら無事に表示されてめでたしめでたし!!
Copy Filesに使いたい画像を入れるのって基本的なことなんですかね、、? よくわからん!


とりあえずtwitterとかのアイコンをパーティクルでどわーっと表示。 

te2