OpenGLES,glDrawArraysを減らしたい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
bonbo

OpenGLES,glDrawArraysを減らしたい

#1

投稿記事 by bonbo » 11年前

描画を行う際にglDrawArraysを減らすと処理効率がよい(軽い)と聞いたのですが
どのように減らしていけばよいのでしょうか。

現在、四角形を描画するにしても

コード:

// 座標と色を設定
const GLubyte squareColors[] =…;
const GLfloat squareVertices[]=…;

コード:

glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
    glEnableClientState(GL_COLOR_ARRAY);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);// 描画
というように描画の度に毎回glDrawArraysを行っているのですが、
これを減らすためにはどうすればよいのでしょうか。

環境はXcode5.0.2でOpenGLESをつかっています。

アバウトな質問で申し訳ないのですが、よろしくおねがいします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: OpenGLES,glDrawArraysを減らしたい

#2

投稿記事 by h2so5 » 11年前

描画するためにはフレームごとに最低1回はglDrawArrays(またはglDrawElements)を呼ばないといけないので、これ以上減らすことはできません。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#3

投稿記事 by bonbo » 11年前

>h2so5さん
ありがとうございます。
質問の仕方を間違えました。本当に申し訳ありません。
やりたいのは以下のようにことなります。

例えば、上記の方法で200回四角形を描画する場合、
1フレームに200回もglDrawArraysを呼び出さないといけない。
そこで、1フレームに呼び出すglDrawArraysの回数を
なるべく減らしたいのだが、どのように実装すればよいか。

ということです。
わかりにくい文章で申し訳ありません。

改めてよろしくお願いします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: OpenGLES,glDrawArraysを減らしたい

#4

投稿記事 by h2so5 » 11年前

頂点配列に200個分の四角形の頂点を入れてglDrawArraysで一度に描画すればできます。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#5

投稿記事 by bonbo » 11年前

>h2so5さん
ありがとうございます。
四角形はできました。(まだ完璧ではないですが)
もう一つ、
この方法で画像を表示する場合についてなのですが、

コード:

// これは今使っている描画のコードです
const GLfloat texCoords[]=...;
const GLubyte squareColors[]=...;
const GLfloat squareVertices[]=...;
glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, g_images[graph.imagenum]);
	
	//頂点座標と色、およびテクスチャの範囲を指定し、描画します
	glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
    glEnableClientState(GL_COLOR_ARRAY);
	glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
のうち、

コード:

const GLubyte squareColors[];
const GLfloat squareVertices[];
の部分をかえればいいのだと思うのですが
その場合、

コード:

GLuint images;
glBindTexture(GL_TEXTURE_2D, images);
は共通していなければなりませんよね。
つまり、"違う画像はこれでまとめることはできない"
のだと思うのですが、あっているでしょうか。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#6

投稿記事 by bonbo » 11年前

どうやら画像の複数同時描画はシェーダというものをつかうみたいですね。
http://d.hatena.ne.jp/homeskill/20120429/1335679181

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: OpenGLES,glDrawArraysを減らしたい

#7

投稿記事 by softya(ソフト屋) » 11年前

openGL ESに詳しくないですが、シェーダの勘違いだけ訂正しておきます。
シェーダはGPUで画素の処理や頂点計算に対してプログラミングを行いたいときに使います。
「シェーダ - Wikipedia」
http://ja.wikipedia.org/wiki/%E3%82%B7% ... C%E3%83%80
今はまだ手を出すの早いかなっと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#8

投稿記事 by bonbo » 11年前

全然ちがいました…
先ほどのやりかたでできるみたいです。
どうやら
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
の第三引数の設定を間違えたみたいで表示がうまく行かなかったようです。
書籍に該当するページをみつけたので、なんとか解決できそうです。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#9

投稿記事 by bonbo » 11年前

>soft屋さん
ありがとうございます。
完全に勘違いでした。
終わったらシェーダについても触れてみようと思います。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: OpenGLES,glDrawArraysを減らしたい

#10

投稿記事 by softya(ソフト屋) » 11年前

bonbo さんが書きました:>soft屋さん
ありがとうございます。
完全に勘違いでした。
終わったらシェーダについても触れてみようと思います。
DirectXの記事ですが、こういう事をするものです。
「プログラマブルシェーダー編」
http://marupeke296.com/ProShader_main.html
エフェクトとかに使いますが、レンダリングの仕組みをちゃんと理解しないと訳わからん状況に陥ると思います。
あと全部のiPhoneで同じように使えないんじゃ無いかと。GPU毎に性能差があります。

こんなのも有るようですが。
「OpenGL ES 2.0 と GLKit - 工場裏のアーカイブス」
http://chemicalfactory.hatenablog.com/e ... /05/234331

まぁ、必要になるまで触らなくても良い気がしますが。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#11

投稿記事 by bonbo » 11年前

>soft屋さん
わざわざありがとうございます。
どうも一足飛びでやろうとする悪い癖がありますよね…

完全に実力不足だと思うので
教えていただいたページなどを参考にする
程度にとどめておこうと思います。

それより基礎をもっと固めるべきですね。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#12

投稿記事 by bonbo » 11年前

できました。
内容自体はh2so5さんがおっしゃってた通りです。
テクスチャの頂点行列を4つで描画していたので
変な表示になっていました。
あとglDrawArraysの第一引数は
GL_TRIANGLES
ですね。
一応コードをのせておきます。

コード:

// 環境によってはstatic_castについて警告されない場合もあります。
#define COUNT 3// 3つ同じ画像を表示
int vertexcount=6;// 頂点行列は4ではなく3*2の6だった
    GLfloat *squareVertices=new GLfloat[vertexcount*2*COUNT];// 頂点6*座標がxyで2*COUNT個の画像を表示
    GLubyte *squareColors=new GLubyte[vertexcount*4*COUNT];// 頂点6*rgbaで4*COUNT個の画像を表示
    GLfloat *texCoords=new GLfloat[vertexcount*2*COUNT];// 頂点6*表示範囲の座標がxyで2*COUNT個の画像を表示
    for (int pari=0; pari<COUNT; pari++) {
// 位置を設定
        float place_left=pari*50;
        float place_right=place_left+static_cast<GLfloat>(16);// ここの16は画像の幅であるから、適宜変える
        float place_top=0;
        float place_bottom=place_top+static_cast<GLfloat>(16);// ここの16は画像の幅であるから、適宜変える
//頂点行列に代入していく
        squareVertices[vertexcount*2*pari+0]=place_left;    squareVertices[vertexcount*2*pari+1]=place_top;
        squareVertices[vertexcount*2*pari+2]=place_right;   squareVertices[vertexcount*2*pari+3]=place_top;
        squareVertices[vertexcount*2*pari+4]=place_left;    squareVertices[vertexcount*2*pari+5]=place_bottom;
        squareVertices[vertexcount*2*pari+6]=place_right;   squareVertices[vertexcount*2*pari+7]=place_top;
        squareVertices[vertexcount*2*pari+8]=place_left;   squareVertices[vertexcount*2*pari+9]=place_bottom;
        squareVertices[vertexcount*2*pari+10]=place_right;  squareVertices[vertexcount*2*pari+11]=place_bottom;
//色を設定するが、簡単のためここでは全ての頂点を255に設定している
        for (int coli=0; coli<vertexcount*4; coli++) {
            squareColors[coli+vertexcount*4*pari]=static_cast<GLubyte>(255);
        }
//left=0.0f,right=1.0f,top=0.0f,bottom=1.0fに設定している
        texCoords[vertexcount*2*pari+0]=static_cast<GLfloat>(left);texCoords[vertexcount*2*pari+1]=static_cast<GLfloat>(top);
        texCoords[vertexcount*2*pari+2]=static_cast<GLfloat>(right);texCoords[vertexcount*2*pari+3]=static_cast<GLfloat>(top);
        texCoords[vertexcount*2*pari+4]=static_cast<GLfloat>(left);texCoords[vertexcount*2*pari+5]=static_cast<GLfloat>(bottom);
        texCoords[vertexcount*2*pari+6]=static_cast<GLfloat>(right);texCoords[vertexcount*2*pari+7]=static_cast<GLfloat>(top);
        texCoords[vertexcount*2*pari+8]=static_cast<GLfloat>(left);texCoords[vertexcount*2*pari+9]=static_cast<GLfloat>(bottom);
        texCoords[vertexcount*2*pari+10]=static_cast<GLfloat>(right);texCoords[vertexcount*2*pari+11]=static_cast<GLfloat>(bottom);
    }
// パラメータをいれ、描画を開始します。
glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, (GLuint型の画像データ));
	
	glVertexPointer(2, GL_FLOAT, 0, squareVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors);
    glEnableClientState(GL_COLOR_ARRAY);
	glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
    glDrawArrays(GL_TRIANGLES, 0, vertexcount*COUNT);// 第一引数はGL_TRIANGLESであることに注意
	
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisable(GL_TEXTURE_2D);

まとめると、
同時に描画可能なのは
ポリゴン(色や形は)と
同じ画像(移す範囲はかえられるので、画像自体を一枚にまとめてしまえば別の映像をうつすこともできる)

だということが分かりました。
今気づいたのですが、たぶん上記二つも同時に描画が可能ですね。

別々の画像の描画を1回にまとめるのはできないようです。

directXなんかだと重たい描画処理自体は一度に全部できたような気がしますが(ありましたよね?裏画面に描画・・・みたいなやつ、以前dxlibraryを使っていたときに見た気がします)、
こちらも似たような処理があるのかもしれません。

つたない説明で分かりにくい点や間違った点もあると思いますが、
あとで見る人の参考になればうれしいです。

h2so5さん、soft屋さん
何度もありがとうございました。

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: OpenGLES,glDrawArraysを減らしたい

#13

投稿記事 by h2so5 » 11年前

一度に複数のテクスチャを利用することは一応できるはずですが、その場合はシェーダーを利用したほうが楽だと思います。
bonbo さんが書きました: directXなんかだと重たい描画処理自体は一度に全部できたような気がしますが(ありましたよね?裏画面に描画・・・みたいなやつ、以前dxlibraryを使っていたときに見た気がします)、
こちらも似たような処理があるのかもしれません。
裏画面に描画してもDrawCallが減るということはありません。全部描画してから表に表示しているだけです。

bonbo

Re: OpenGLES,glDrawArraysを減らしたい

#14

投稿記事 by bonbo » 11年前

(※)上記コードについて補足ですが、このままだとリークが
生じてしまっているので
newで生成した変数はちゃんと解放しないといけませんでした。
もし利用される方がいらっしゃいましたら、
最後にfreeなどで解放してあげてください。
お手数おかけします。

>h2so5さん
ありがとうございます。
適当なことを言って申し訳ありませんでした。

なんとなく、イメージなんですが
(画面の幅)*(画面の高さ)個ピクセルに、それぞれの最終的な色の情報を与えて、
それを一回だけ画面に出力できたら一番効率よいのではないか?
と思っていました。
アルファブレンディングなども数値的な計算で可能ですよね?
リファレンスなどにもglDrawarraysについてはそんなに詳しいことはのっていなかったのですが
そもそもピクセルに情報を伝えるのが重たい処理なのかもしれません。
・・・また憶測になってしまいましたが。

http://www.opengl.org/sdk/docs/man4/xht ... Arrays.xml

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前
住所: 東京
連絡を取る:

Re: OpenGLES,glDrawArraysを減らしたい

#15

投稿記事 by h2so5 » 11年前

プログラムを処理している部分(CPU)と、画面への出力を処理している部分(GPU)は離れた場所にあると思ってください。

例えばあなたが離れた場所に家を立てたいとして、
1) 設計図と材料だけその場所へ送って大工さんに組み立ててもらう
2) 全部自分で組み立ててから家をその場所へ移動させる
のどちらが効率がいいかは明らかですよね。

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: OpenGLES,glDrawArraysを減らしたい

#16

投稿記事 by ISLe » 11年前

テクスチャを切り替えること自体がネックなのでまとめられるならまとめたほうが良いと思います。

以前どこかで見ましたがトライアングルストリップで独立した四角形を複数描く方法もあります。
余分な手間がかかるし直感的ではないのであまりお勧めできる方法ではないと思いますが。

glDrawArraysを減らすのも良いですが、頂点データをVBOにして使い回したらもっと効果があるんじゃないですかね。
VBOはOpenGL ES 1.1以降で使えます。

閉鎖

“C言語何でも質問掲示板” へ戻る