ラベル OpenGL の投稿を表示しています。 すべての投稿を表示
ラベル OpenGL の投稿を表示しています。 すべての投稿を表示

2015年6月29日月曜日

OpenGLのサンプルをやってみたPart2

OpenGLのサンプルをやってみたPart2

もう少しOpenGLの理解を深めるためにネットに転がっているサンプルをやってみようと思います。
ということで今回は以下。
http://utage.headwaters.co.jp/blog/?p=1724

サンプルソースもすべて公開されており、ソースにコメントもあるので
大変勉強になったのですが、初心者にとっては理解ができないところがあったので、メモを残したいと思います。

renderMainでglMatrixModeを2回設定しているのはなぜ?

座標系としては透視投影(奥行きによって、大きさが変わる)ような表示をしたいので、
視体積を設定するglFrustumfの前にGL_PROJECTIONとして設定し、それ移行のオブジェクトはモデルビューで設定したいからっぽい。

テクスチャ画像ファイルは2の階乗になっていないといけない (128px*128pxなど)??

 と書いてあったが以下の解像度を試しましたがリードできてました。
 1600x1200
 278x204
 1333x1000
 1600x1600

使った画像は以下です。一応著作権フリーのもの。
enter image description here

キャラの周りが透明にならない。

上記のキャラの周りは透明(アルファ=0)にも関わらず以下のように周りが黒くなってしまいました。

enter image description here

renderMainに以下を追加することで解決しました。

gl.glEnable(GL10.GL_ALPHA_TEST);
gl.glAlphaFunc(GL10.GL_GEQUAL, 0.1f);

これはアルファ値が0.1f以上は描画するということなので、逆にいうとアルファ値が0の部分は描画されなくなったということです。ちなみに黒となっていたのはアルファ値が0の部分のRGB値がすべて0となっていたためです。

gl.glFrustumfって何?

 透視投影への視体積の設定。  引数は、以下の順。
  Nearの左側の座標
  Nearの右側の座標
  Nearの上側の座標
  Nearの下側の座標
  Nearの距離
  Farの距離

  gl.glFrustumfの引数を変えて見え方がどう変わるかを実験をしてみました。
     

実験 変数 画像 コメント
オリジナル -0.3f, 0.3f, -0.2f, 0.2f, 0.5f, 20.0f enter image description here
実験1 -0.5f, 0.5f, -0.2f, 0.2f, 0.5f, 20.0f enter image description here 透視投影だと遠くにいくほど大きくなるので、奥行き感がなくなると想定していたが、逆に奥行き感が増えた。よくわからない。
実験2 -0.3f, 0.3f, -0.5f, 0.5f, 0.5f, 20.0f enter image description here Nearの縦方向を大きくすることでFar方向の縦の距離の差が減るので縦方向が狭まった。
実験3 -0.3f, 0.3f, -0.2f, 0.2f, 1.0f, 20.0f enter image description here 見ている視点がZ=1.0fの為か手前側しか見えない
実験4 -0.3f, 0.3f, -0.2f, 0.2f, 0.2f, 20.0f enter image description here オリジナルよりNearとFarの距離が増えたので奥行きが広がった?
実験5 -0.3f, 0.3f, -0.2f, 0.2f, 0.5f, 10.0f enter image description here オリジナルと変わらない。10.0fも20.0fも同じ? 試しに5.0fにしても変わらなかった。
実験6 -0.3f, 0.3f, -0.2f, 0.2f, 0.5f, 1.0f enter image description here ねこより後ろが表示されていない
実験7 -0.3f, 0.3f, -0.2f, 0.2f, 0.5f, 2.0f enter image description here ねこより後ろが表示されるようになったが、空が表示されていない
実験8 -0.3f, 0.3f, -0.2f, 0.2f, 0.5f, 3.0f enter image description here オリジナルと同じになった

参考
http://seesaawiki.jp/w/mikk_ni3_92/d/%BC%C2%C1%A9%CA%D407
https://sites.google.com/a/gclue.jp/android-docs-2009/openglno-kiso
http://www.kameda-lab.org/lecture/2012-tsukuba-ic2/chapter08-j.html
http://ameblo.jp/xcc/entry-10276958074.html

gl.glTranslatefって何?

移動の設定。

実験 変数 画像 コメント
オリジナル 0.0f, 0.0f, -1.0f enter image description here
実験1 0.0f, 0.0f, 0.0f enter image description here
実験2 0.0f, 0.0f, -2.0f enter image description here
実験3 -1.0f, 0.0f, -1.0f enter image description here 左に移動したので右半分がでていない。
実験4 0.0f, -1.0f, -1.0f enter image description here 下に移動したので、上のほうがでていない

gl.glRotatefで-70.0fってなぜ-70.0f?

回転。X,Y,,Zどの軸を基準に回転させるか?
以下のように実験してみたが、-70.0fは結構いい感じで奥行き感がでている。

実験 変数 画像 コメント
オリジナル -70.0f,1.0f, 0.0f, -1.0f enter image description here
実験1 0.0f,1.0f, 0.0f, -1.0f enter image description here
実験2 -45.0f,1.0f, 0.0f, -1.0f enter image description here
実験3 -90.0f,1.0f, 0.0f, -1.0f enter image description here
実験4 90.0f,1.0f, 0.0f, -1.0f enter image description here
実験5 -80.0f,1.0f, 0.0f, -1.0f enter image description here
実験6 -60.0f,1.0f, 0.0f, -1.0f enter image description here

GraphicUtil.drawTextureって何?

ウインドウにテクスチャを貼り付ける方法の設定。

引数 説明
GL10 gl
float x テクスチャを貼り付けるウインドウの座標(x)左が0
float y テクスチャを貼り付けるウインドウの座標(y)上が0
float width 1倍なら1.0f?
float height 1倍なら1.0f?
int texture テクスチャのID。GraphicUtil.loadTextureで取得
float u テクスチャの横座標。左が0.0f
float v テクスチャの縦座標。上が0.0f
float tex_w テクスチャの横幅。最大1.0f
float tex_h テクスチャの縦幅。最大1.0f
float r 赤。 1.0fならテクスチャの赤をそのまま表示
float g 緑。 1.0fならテクスチャの緑をそのまま表示
float b 青。 1.0fならテクスチャの青をそのまま表示
float a アルファ 1.0fならテクスチャのアルファをそのまま表示
引数 説明
オリジナル enter image description here
実験1 width,hightを1.0f,1.0fに変更 enter image description here
実験2 width,hightを3.0f,1.0fに変更 enter image description here
実験3 width,hightを1.0f,3.0fに変更 enter image description here

gl.glPushMatrixって何?

行列スタックの一番上の行列をコピーして、その上に積む。
積まれた行列をスタックからとりだすときは、gl.PopMatrixで取り出す。

なぜ必要?

複数のオブジェクトを描画するときに、基準となる座標を1つ前に描画されたオブジェクト基準ではなく、常に同じ座標を基準に描画するようにする手段っぽい。

もう少し具体的にいうと
描画されるのは一番上のスタックにある行列で、
Translate, Rotateなどに描画に必要な操作はスタックの一番上の行列に対して計算されている。

この状態で次のオブジェクトを描画しようとすると、座標は1つ前の座標基準に考えなければならない。

Push,Popを使うことで
Push(コピー)されたものに対してTranslate, Rotateなどに描画するための演算をし、描画されたらその行列をPopで取り除くことで元の座標基準で描画できるというしくみ。
このサンプルでは地面を最初に描画しているが、地面は、座標をいじっていないのでPush/Popはしていない?

OpenGLでゲームを作る 図形の描画に非常にわかりやすく書いてあります。

使い方としては、以下のような形でPushとPopの間で描画する。

 gl.glPushMatrix();
{
            gl.glTranslatef(0.0f,1.5f,0.5f);  // y軸方向に1.5f,z軸方向に0.5f移動させる
            gl.glRotatef(90.0f, 1.0f,0.0f,0.0f);  // x軸を中心に90度回転
            // 奥背景の描画
            GraphicUtil.drawTexture(gl, 0.0f, 0.0f,
                    2.0f,1.0f,  // width, height
                    backTex,
                    0.0f,0.0f,
                    1.0f,1.0f,
                    1.0f,1.0f,1.0f,1.0f);
        }
        gl.glPopMatrix();

gl.glOrthofって何?

正射影の設定。
画面上の中央が(0, 0)、画面横の長さが2.0、画面縦の長さが3.0という座標系を指定している。奥行きに関しては手前が-1.0fで奥が1.0f。
だいたい画面縦横比は2:3なので、こうしているっぽい。

参考
http://news.mynavi.jp/column/iphone/019/

2015年6月23日火曜日

OpenGLでの描画

OpenGLでの描画

OpenGLを使って描画する。

三角形を例にします。
流れとしては頂点を設定して、描画って感じです。

頂点の設定

以下の手順で頂点を設定します。

Step1. 頂点の座標(X,Y,Z)を配列で定義する。

float[] vertices = {
  0.0f, 1.0f, 0.0f, //頂点0 (上)
  0.0f, 0.0f, 0.0f, //頂点1 (左下)
  1.0f, 1.0f, 0.0f, //頂点2 (右上)
};

Step2. バッファのメモリ確保

座標データ数x4倍のメモリを確保します。
※4倍しているのはfloatが4byte扱いの為。

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);

Step3. ネイティブのエンディアン指定

nativeのエンディアンを取得し、設定します。

vbb.order(ByteOrder.nativeOrder());

Step4. ByteBuffer型のオブジェクトをFloatBufferに変換

FloatBuffer mVertexBuffer = vbb.asFloatBuffer();

Step5. Step4で変換されたFloatBufferに最初の頂点座標(float配列)をセット

mVertexBuffer.put(vertices);

Step6. 書き込み位置の調整
書き込みが発生するたびに次書き込むための位置が1進んでしまうため、それを戻す処理を行っています。

mVertexBuffer.position(0);

[参考]
http://librastudio.hatenablog.com/entry/2013/08/19/010615

描画の設定

Step1. 頂点配列を有効にする。

   glEnableClientState(int array)を使って、どの配列を使って、描画するかを指定します。
   今回の場合は、頂点を設定しているので引数は、GL_VERTEX_ARRAYとする。
   

変数 意味 参照
GL_COLOR_ARRAY カラー配列 glColorPointer()
GL_EDGE_FLAG_ARRAY エッジフラグ配列 glEdgeFlagPointer()
GL_INDEX_ARRAY 指標配列 glIndexPointer()
GL_NORMAL_ARRAY 法線配列 glNormalPointer()
GL_TEXTURE_COORD_ARRAY テクスチャ座標配列 glTexCoordPointer()
GL_VERTEX_ARRAY 頂点配列 glVertexPointer()

glEnableClientState(GL10.GL_VERTEX_ARRAY);

Step2. 頂点配列を定義する。

glVertexPointer((int size, int type, int stride,java.nio.Buffer pointer)

変数 意味 備考
size 頂点データのサイズ 2次元なら2,3次元なら3,Wを含めるなら4
type GL_SHORT、GL_INT、GL_FLOAT、GL_DOUBLE
stride 連続する頂点間でのバイト・オフセット 0 を指定すれば、頂点の情報が配列ないに隙間なく入っている
pointer 座標情報を含む配列へのポインタ

X,Y,Z座標を指定しているのでsizeは3。

glVertexPointer(3,GL10.GL_FLOAT,0,mVertexBuffer);

Step3. 法線ベクトルの追加

ここでいう法線ベクトルとは・・・  面に垂直な長さが1のベクトル。

1)p0→p1という向きのベクトルv1(= p1 - p0)の算出
2)同様に、p0→p2という向きのベクトルv2(= p2 - p0)の算出。
3)v2からv1への外積v2×v1の算出
4)外積の長さの算出
5)外積をその長さで割り、正規化する。  

※glEnable(GL_NORMALIZE)とすれば法線ベクトルを単位ベクトルにする必要はないようです。

今回の場合は、以下なので
0.0f, 1.0f, 0.0f, //頂点0 (上)
0.0f, 0.0f, 0.0f, //頂点1 (左下)
1.0f, 1.0f, 0.0f, //頂点2 (右上)

1) p1-p0 = 0.0f, -1.0f, 0.0f
2) p2-p0 = 1.0f, 0.0f, 0.0f
3)外積は以下で求めると、
 -1*0-0*0,0*1-0*0,0*0-(-1*1)=0.0f, 0.0f,1.0f
 となる。




なので、

4) 外積の長さは以下のようにすでに1なので、単位ベクトルになっている。

ので、

glNormal3f(0.0f, 0.0f, 1.0f)

※四角形の場合は三角形2つに分割して、その三角形2つの面法線ベクトルを平均化するらしい
※三角形の場合はなくても描画できました。

Step4. 描画

glDrawArrays(int mode,int first,int count)を使って描画します。
描画する面に対してglNormal, glDrawArraysをペアで設定する必要があります。
三角形の場合は1つでよいが立方体の場合は6面あるので、6ペア必要です。

変数 意味
mode 描画方法
first はじめに描画する頂点番号
count 描画する頂点数

今回の場合は三角形を塗りつぶしたいので、以下でいいようです。

glDrawArrays(GL10.GL_GL_TRIANGLES, 0, 3);

参考
http://sky.geocities.jp/freakish_osprey/opengl/opengl_normalvecotr.htm
http://opengl.softwarecarpenter.biz/?eid=1075451
http://atelier-yoka.com/dev_android/p_main.php?file=apigl10gldrawarrays