OpenGLESの雛形について2

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
TOMY
記事: 53
登録日時: 13年前
住所: 愛知県
連絡を取る:

OpenGLESの雛形について2

#1

投稿記事 by TOMY » 12年前

前回 → http://dixq.net/forum/viewtopic.php?t=11028&p=88746

だいぶ昔のトピックの続きですが、一応制作は進めていました。オライリーの『初めてのOpenGLES』を参考に雛形を作っていて問題が多々出てきてしまったために質問させて頂きます。
非常にワガママ身勝手ですが、案の定また制作締め切りが近づいていて、しかもこれが出来なければチーム制作の他の人の評価に影響を出してしまうため、出来れば早急にアドバイスが頂きたのでお願いします。

本題です。夏休みの頃から、オライリーの初めてのOpenGLESを参考に雛形を作って、ポリゴンの描画を簡単にする『GL2DVertex』クラスにて、radian値を入力すればその値にあわせて矩形ポリゴンが回転するという処理を入れていましたが、うまく出来ずに詰まってしまいました。そこでOpenGLに詳しい先生に相談してみたところ、glorthof関数で座標系を作っていないため、このままでは汎用性のないものになってしまうと指摘され、glorthofを使い、左上頂点のウィンドウ座標系をつくりました。しかし、今度はポリゴンの描画部分がおかしくなってしまい、その部分を解決する方法を緊急で模索しています。
問題のプログラム部分はここです。↓

コード:

//ポリゴンの生成、更新、描画を簡単にさせるためのクラス

package jp.denpa.tomy.opengl_es.wrap;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.math.*;

import javax.microedition.khronos.opengles.GL10;



public class GL2DVertex {

	public Vector2 center;			//中心座標
	public Vector2 size;			//ポリゴンサイズ
	public float   rad;				//回転角度(radian)

	private GL10   gl10;
	private float a,r,g,b;			//カラー+アルファ

	// 持っておきたい情報
	private int		useTexName;		// 使用するテクスチャ番号
	private boolean	turnFlg;		// テクスチャのUVを左右反転

	//壊れることのない情報(配列定数)
	private final static float[] dx={-1.0f, 1.0f, 1.0f, -1.0f};
	private final static float[] dy={-1.0f, -1.0f, 1.0f, 1.0f};

	//計算が分かりやすい様にする為の変数
	private float[] tx = new float[4];
	private float[] ty = new float[4];

	public GL2DVertex(GL10 gl){
		this.gl10 = gl;
	}

	public void Init(){		//初期化



		useTexName	= -1;
		turnFlg		= false;
		rad			= 0;
		//色の初期設定
		a=1.0f;
		r=1.0f;
		g=1.0f;
		b=1.0f;
//		float uv[] = {
//				1,0,		//左上
//				1,1,		//右上
//				0,1,		//右下
//				0,0,		//左下
//		};
//		ByteBuffer bb = ByteBuffer.allocateDirect(uv.length * 4);
//		bb.order(ByteOrder.nativeOrder());
//		FloatBuffer fb = bb.asFloatBuffer();
//		fb.put(uv);
//		fb.position(0);

//		gl10.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		//gl10.glTexCoordPointer(2, GL10.GL_FLOAT, 0, fb);
	}

	public void SetUV(int cx,int cy,int nx,int ny,boolean turn){		//UV座標セット(cx,cy=分割数。 nx,ny=描画番号 ※左上原点でお考えください)
		float w = 1.0f/cx;
		float h = 1.0f/cy;

		float left	= w * nx;
		float top	= h * (ny+1);
		float right	= w * (nx+1);
		float bottom= h * ny;

		if(turn==true){			//反転フラグがtrueの時の処理
			float tu=right;
			right=left;
			left=tu;
		}
		float uv[] = {			//UV座標
			left,bottom,		//左下
			left,top,			//左上
			right,top,			//右上
			right,bottom,		//右下
		};

		ByteBuffer bb = ByteBuffer.allocateDirect(uv.length * 4);
		bb.order(ByteOrder.nativeOrder());
		FloatBuffer fb = bb.asFloatBuffer();
		fb.put(uv);
		fb.position(0);

		gl10.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl10.glTexCoordPointer(2, GL10.GL_FLOAT, 0, fb);				//ストリームに登録

	}

	public void SetUV(int cx,int cy,int nx,int ny){
		float w = 1.0f/cx;
		float h = 1.0f/cy;

		float left	= w * nx;
		float top	= h * (ny+1);
		float right	= w * (nx+1);
		float bottom= h * ny;

		if(turnFlg==true){			//反転フラグがtrueの時の処理
			float tu=right;
			right=left;
			left=tu;
		}
		float uv[] = {			//UV座標
			left,bottom,		//左下
			left,top,			//左上
			right,top,			//右上
			right,bottom,		//右下
		};

		ByteBuffer bb = ByteBuffer.allocateDirect(uv.length * 4);
		bb.order(ByteOrder.nativeOrder());
		FloatBuffer fb = bb.asFloatBuffer();
		fb.put(uv);
		fb.position(0);

		gl10.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl10.glTexCoordPointer(2, GL10.GL_FLOAT, 0, fb);				//ストリームに登録

	}

	public void SetColor(float A,float R,float G,float B){		//色の設定
		a=A;r=R;g=G;b=B;
	}

	private void SetPos(){		//座標の更新(確定)		//あとで回転の計算も入れる

		float[] verX = new float[4];
		float[] verY = new float[4];

		//計算の簡略化用
		for(int i=0;i<4;i++){
			tx[i] = size.x / 2 * dx[i];
			ty[i] = size.y / 2 * dy[i];
		}
		for(int i=0;i<4;i++){
			verX[i] = (float) (tx[i] * Math.cos(rad) - ty[i] * Math.sin(rad) + center.x);
			verY[i] = (float) (tx[i] * Math.sin(rad) + ty[i] * Math.cos(rad) + center.y);
		}

		//位置情報
		float positions[] = {			//x,y,zの順に定義
				verX[0],verY[0],0,			//左上
				verX[1],verY[1],0,			//右上
				verX[2],verY[2],0,			//右下
				verX[3],verY[3],0,			//左下
		};
//		float positions[] = {			//x,y,zの順に定義
//				50,50,0,			//左上
//				100,50,0,			//右上
//				100,100,0,			//右下
//				50,100,0,			//左下
//		};

		//OpenGLはビッグエンディアンではなく
		//CPUごとの”ネイティブエンディアン”で数値を伝える必要がある。
		//その為Javaヒープを直接的には扱えず、
		//”Java.nio”配下のクラスへ一度値を格納する必要がある。(面倒くせぇ)
		ByteBuffer bb=ByteBuffer.allocateDirect(positions.length * 4);  //GL_ESが扱えるのはallocateDirectで確保した領域のみ
		bb.order(ByteOrder.nativeOrder());		//実行環境に合わせて最適な値を指定できるようにnativeOrderを使う
		FloatBuffer fb = bb.asFloatBuffer();	//確保したバッファをfloatに格納(新たにメモリを確保しているわけではない)
		fb.put(positions);						//バッファをfloat配列に転送(この時点でエンディアンに関する変換はもう終わっている)
		fb.position(0);							//putすると書き込み位置が一つ進められるのでpositionで最初に戻す

		gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl10.glVertexPointer(3,GL10.GL_FLOAT,0,fb);				//OpenGL ESに頂点バッファを関連付ける(コピーではないことに注意)

	}

	public void Draw(GLTexture gltex){		//描画

		//ビューポート変換
		gl10.glViewport(0,0,MainRenderer.screenW,MainRenderer.screenH);

		//投影変換
		gl10.glMatrixMode(GL10.GL_PROJECTION);
		gl10.glLoadIdentity();
		gl10.glOrthof(0,MainRenderer.screenW,-MainRenderer.screenH,0 , -10,10);			//座標系の指定(左上原点Wndow座標系指定(ニア、ファーは0にして2D専用にしている))
//		gl10.glTranslatef(-MainRenderer.screenW/2, -MainRenderer.screenH/2, 0);			//座標系の原点を平行移動
//
		SetPos();
		// テクスチャ有り
		gl10.glBindTexture(GL10.GL_TEXTURE_2D, gltex.getTexName());
		gl10.glDrawArrays(GL10.GL_TRIANGLE_FAN,0,4);		//描画

	}

	public void Draw(){
		//ビューポート変換
		gl10.glViewport(0,0,MainRenderer.screenW,MainRenderer.screenH);

		//投影変換
		gl10.glMatrixMode(GL10.GL_PROJECTION);
		gl10.glLoadIdentity();
		gl10.glOrthof(0,MainRenderer.screenW,-MainRenderer.screenH,0 , -10,10);			//座標系の指定(左上原点Wndow座標系指定(ニア、ファーは0にして2D専用にしている))
//		gl10.glTranslatef(-MainRenderer.screenW/2, -MainRenderer.screenH/2, 0);			//座標系の原点を平行移動
//

		//クリア色の設定
		gl10.glClearColor(a,r,g,b);

		SetPos();

		//モデリング変換
		gl10.glMatrixMode(GL10.GL_MODELVIEW);
		gl10.glLoadIdentity();

		gl10.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, 4);
}

	public void SetTexName(int texname)		{ useTexName = texname; }
	public void SetTurnFlg(boolean turnflg)	{ turnFlg 	 = turnflg;	}

	public int GetTexName()					{ return useTexName;	}
	public boolean GetTurnFlg()				{ return turnFlg;		}

}
この掲示板、自分だけかもしれませんがなぜか長文を書くと変な動作を起こしてしまうため複数に分けて投稿します。
百聞は一見にしかず。うんちくだけを頭にぶち込む前に実際に実験した方がいいよ。
書籍とか経験談とか見て知識をつけるのも大事だけど。

アバター
TOMY
記事: 53
登録日時: 13年前
住所: 愛知県
連絡を取る:

Re: OpenGLESの雛形について2

#2

投稿記事 by TOMY » 12年前

GL_ES_GAME_BASEver1.03bug.zip
(3.02 MiB) ダウンロード数: 131 回
続きです。
動作がおかしくなっている部分はクラス内のせSetPosメソッドの中の

コード:

	private void SetPos(){		//座標の更新(確定)		//あとで回転の計算も入れる

		float[] verX = new float[4];
		float[] verY = new float[4];

		//計算の簡略化用
		for(int i=0;i<4;i++){
			tx[i] = size.x / 2 * dx[i];
			ty[i] = size.y / 2 * dy[i];
		}
		for(int i=0;i<4;i++){
			verX[i] = (float) (tx[i] * Math.cos(rad) - ty[i] * Math.sin(rad) + center.x);
			verY[i] = (float) (tx[i] * Math.sin(rad) + ty[i] * Math.cos(rad) + center.y);
		}

		//位置情報
		float positions[] = {			//x,y,zの順に定義
				verX[0],verY[0],0,			//左上
				verX[1],verY[1],0,			//右上
				verX[2],verY[2],0,			//右下
				verX[3],verY[3],0,			//左下
		};
		//OpenGLはビッグエンディアンではなく
		//CPUごとの”ネイティブエンディアン”で数値を伝える必要がある。
		//その為Javaヒープを直接的には扱えず、
		//”Java.nio”配下のクラスへ一度値を格納する必要がある。(面倒くせぇ)
		ByteBuffer bb=ByteBuffer.allocateDirect(positions.length * 4);  //GL_ESが扱えるのはallocateDirectで確保した領域のみ
		bb.order(ByteOrder.nativeOrder());		//実行環境に合わせて最適な値を指定できるようにnativeOrderを使う
		FloatBuffer fb = bb.asFloatBuffer();	//確保したバッファをfloatに格納(新たにメモリを確保しているわけではない)
		fb.put(positions);						//バッファをfloat配列に転送(この時点でエンディアンに関する変換はもう終わっている)
		fb.position(0);							//putすると書き込み位置が一つ進められるのでpositionで最初に戻す

		gl10.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl10.glVertexPointer(3,GL10.GL_FLOAT,0,fb);				//OpenGL ESに頂点バッファを関連付ける(コピーではないことに注意)

	}
位置情報の格納部分です。
各頂点の座標を計算(回転も可能)し、それを1次元のfloat配列にTRIANGLE_FAN形式で格納、java.nioを使い、OpenGLESの使用可能な形に変換・・・としているつもりなのですが、
実際に実行してみると何も表示されません。自分はByteBuffer関連の部分が怪しいのではないかと思っているのですが、そこまでハード的な部分は詳しくないのでわかりません。
正直このポリゴン描画とテクスチャが貼られたポリゴンが描画できて、回転もしてくれれば一応の完成なのですが・・・
プロジェクトも一緒に添付しておきます。一つ目は実際に問題の出ているプロジェクトです。(bugとついている方)
もう一つは回転の計算式を入れる前に動いた方のプロジェクトです。(一部変なところがあります【設定はTRIANGLE_FANなのに配列の格納がTRIANGLE_STRIPになっている点など】)
※追記:単位はピクセル単位のつもりです。
添付ファイル
GL_ES_GAME_BASEver1.02.zip
(3.02 MiB) ダウンロード数: 134 回
百聞は一見にしかず。うんちくだけを頭にぶち込む前に実際に実験した方がいいよ。
書籍とか経験談とか見て知識をつけるのも大事だけど。

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

Re: OpenGLESの雛形について2

#3

投稿記事 by ISLe » 12年前

glOrtho(f)は座標系を設定する命令ですが、同時に射影変換が正射影モードになります。

前回のスレでも書きましたけど、ビューポートや座標系をポリゴンひとつ描画する度に変更するような設計は汎用性があるとかないとか以前のレベルです。

ポリゴンひとつ描画するクラスにglOrthoは関係ありません。
あるいはGL2DVertexは画面にポリゴンひとつしか描画しないアプリケーション専用なのでしょうか。

ビューポートや座標系というのは画面のどこにどのように描画した結果を投影するかの設定です。
描画コードを変えずとも、ビューポートや座標系を変更するだけで、画面いっぱいに描画していたものを画面半分にしたり上下左右を反転したりできるわけですが、ポリゴンひとつ描画するのに都合の良いようにいちいち変更してしまえば簡単に破綻します。

GL2DVertexはポリゴンの描画だけを行うべきですし、ビューポートや座標系の設定はすべての描画に先立って行われるべきです。

(追記)
とりあえず、描画されないのはglOrthofの座標系設定の誤りです。
Yの座標系が0~『マイナス』画面サイズになっています。

アバター
TOMY
記事: 53
登録日時: 13年前
住所: 愛知県
連絡を取る:

Re: OpenGLESの雛形について2

#4

投稿記事 by TOMY » 12年前

学校の体育祭があったため、ご返信が遅くなってしまい申し訳ございません。

ILSeさんのおっしゃるとおり、指摘された部分を修正したら画像が表示されました。思っていたのと違う形でしたが。
そこの修正がてら、先ほどのご返答で一つ疑問があったため質問させて頂きます。
ISLeさんの、ポリゴンを描画するたびに座標系を変更という部分なのですが。
それならば、2Dで背景を表示して、3D空間上にオブジェクトを配置。その上にヘッドアップディスプレイとして2Dで画像を描画したい場合はどうすればいいのでしょうか?
百聞は一見にしかず。うんちくだけを頭にぶち込む前に実際に実験した方がいいよ。
書籍とか経験談とか見て知識をつけるのも大事だけど。

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

Re: OpenGLESの雛形について2

#5

投稿記事 by ISLe » 12年前

TOMY さんが書きました:それならば、2Dで背景を表示して、3D空間上にオブジェクトを配置。その上にヘッドアップディスプレイとして2Dで画像を描画したい場合はどうすればいいのでしょうか?
まずビューポートを設定し
2Dの背景をまとめて描画する直前に一回だけ座標系を設定し
3Dオブジェクトをまとめて描画する直前に一回だけ座標系を設定し
2Dオブジェクトをまとめて描画する直前に一回だけ座標系を設定する
ですが。

2D背景と、3Dオブジェクトと、2Dオブジェクトの座標系はそれぞれ異なっていてもかまいませんが、どういう座標系にするかは設計段階で決まっている必要があります。
そうしなければ2D背景、3Dオブジェクト、2Dオブジェクトの配置座標がふらふらしてしまいます。
逆にビューポートはデバイス画面のどこでも好きな位置に好きな大きさ縦横比でスクリーンを描画するように変更できます。

現状だと画面いっぱいを一対一のピクセル比で描画するという仕様に固定されてしまうのですが、それで問題ないと思ってますか?
例えばレースゲームのバックミラーの映像をレンダリングするとして、画面全体を描画対象に設定してしまうメソッドが紛れていたらどう思います?

GL2DVertexクラスを使うために、左上原点で画面いっぱいを描画対象と考えてコードを書かなければならないとしたら仕様と実装の逆転です。

アバター
TOMY
記事: 53
登録日時: 13年前
住所: 愛知県
連絡を取る:

Re: OpenGLESの雛形について2

#6

投稿記事 by TOMY » 12年前

また、返事が遅れてしまい申し訳ございません。学校行事が重なってなかなか、ここにアクセス出来ませんでした。ISLeさんのアドバイスの内容を理解して、誠に身勝手ながら、急いで組み立てるので、しばらくこのスレッドを保留させてもらいます。あと、描画の問題ですが、画面の回転時に座標がぐちゃぐちゃになっているような気配があったので伝えておきます。
何度か回転させると意図した位置とは別の場所に変な形で表示されていたので、おそらく本体の座標が正しく取れていないのかもしれません。
百聞は一見にしかず。うんちくだけを頭にぶち込む前に実際に実験した方がいいよ。
書籍とか経験談とか見て知識をつけるのも大事だけど。

アバター
TOMY
記事: 53
登録日時: 13年前
住所: 愛知県
連絡を取る:

Re: OpenGLESの雛形について2

#7

投稿記事 by TOMY » 12年前

前置きに。いまさらですがこのトピックの続きを投稿させてもらいます。
半月以上もの期間なんの投稿もなく、申し訳ございません。

以下本題ですが、
座標系についてはISLeさんの意見を参考にさせてもらいます。今は3次元の描画は一切考えてないのでプログラムに記述していませんが。
あのあと、パンカクの『OpenGLで作るAndroid SDK ゲームプログラミング』に記載されていたテクスチャマネージャーを参考にBGMとSEを管理するマネージャーもどきを作り、追加しました。未だに描画の度、頂点情報を計算したり転送したりと不効率なのですが。いずれは頂点情報などが変化ない場合は転送をしないなど、すべてのオブジェクトで管理するVBO(Vertex Buffer Object)マネージャーなるものを作ろうとは思っています。が、まだ作っておりません。
また一応の収束(前述のVBOマネージャーが実装されていなかったり、テクスチャサイズが取得できないなどの問題はありますが)をしたものをアップロードさせてもらいます。
またこのトピック自体すごく不定期な更新状態だったので一応のけじめとして解決マークを出させて頂きます。
(まだ解決できていない問題などもあってまた投稿すると思いますが)

多くの方に迷惑をおかけしてすみませんでした。
添付ファイル
GL_ES_GAME_BASEver1.10(VBOマネージャ未完成、テクスチャサイズバグあり).zip
(7.56 MiB) ダウンロード数: 139 回
百聞は一見にしかず。うんちくだけを頭にぶち込む前に実際に実験した方がいいよ。
書籍とか経験談とか見て知識をつけるのも大事だけど。

閉鎖

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