OpenGLでの画面の拡縮について

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

OpenGLでの画面の拡縮について

#1

投稿記事 by 奥兵 » 11年前

現在Android端末で動くシューティングゲームを制作しています。
描画部分はSurfaceViewでピクセルを直接指定して描画していたのですが、これではAndroid端末の解像度や画面サイズによって画面が大きく余ったり見切れたりしてしまいます。
そこでそれを修正したいと思い、いろいろ調べてみるとOpenGLで描画すると描画した画面全体を拡縮できるという旨の記述を発見しました。
早速、いろいろなサイトを参考に描画部分のOpenGLへの切り替えを図ったのですが肝心の画面に合わせての拡縮の部分が自分の知識では参考になるサイトや記述を見つけられませんでした。

実現させたいのは、既にピクセル指定で出現テーブル等を用意してあるのでそれをそのまま描画し、描画された画面全体を端末サイズに合わせ縦か横を基準に拡縮して描画することです。

3Dは完全な素人で、いろいろ調べつつ拡大行列を描画されたもの全体に掛けるらしい、というところまではわかったのですが、3D関連の語彙が無いもので行き詰まってしまいました。
アドバイスやキーワードなどをいただけると幸いです。

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

Re: OpenGLでの画面の拡縮について

#2

投稿記事 by h2so5 » 11年前

OpenGLでの描画というのを具体的にどのような手順で行なっているのかよく分からないので答えにくいです。
拡大縮小なしでOpenGLで描画することはできるんですよね?

頂点シェーダーを変更できるのであればそこに拡大縮小の処理を入れることができますが。

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

Re: OpenGLでの画面の拡縮について

#3

投稿記事 by ISLe » 11年前

SurfaceViewからの移行ということなので2Dですよね。

GLSurfaceViewに下記のようにコードを記述すれば、[ゲーム画面の幅]x[ゲーム画面の高さ]の座標に描画したものがView全体に拡大あるいは縮小して表示されます。

コード:

        public void onSurfaceChanged(GL10 gl, int w, int h) {
            gl.glViewport(0, 0, w, h);
            gl.glMatrixMode(GL10.GL_PROJECTION);
            GLU.gluOrtho2D(gl, 0.0f, [ゲーム画面の幅], 0.0f, [ゲーム画面の高さ]);
        }

奥兵

Re: OpenGLでの画面の拡縮について

#4

投稿記事 by 奥兵 » 11年前

御二方早速のお返事ありがとうございます。家を空けていまして、返信が遅くなって申し訳ないです。

h2so5さん。
OpenGLは基礎部分は 
http://android.keicode.com/basics/opengl-overview.php
このサイトをほとんど完全に参考にして、
2Dというかスプライトはというかは
http://blog.oukasoft.com/%E3%83%97%E3%8 ... %E3%83%81/
こちらのサイトを、これもほぼ完全に参考にしました。

ISLeさん。
はい、2Dのゲームです。
教えて頂いたコードでonSurfaceChangedを書き換えてみました。そして試しに画面左下に64*64の画像を縦横を三倍ずつしたものを表示して、
もととなる画面の幅と高さの設定を32ずつにして、画像が拡大表示されるか実験してみたのですが。コードを入れ替える前と変わらず描画されてしまいます。
私のコードか実験方法に問題があるとおもうので、とりあえずもうすこし実験してみます。

実験用プロジェクトのGLSurfaceViewの継承クラスにセットしているレンダラー部分です。1,2割の理解で、儀式的に参考サイトのものを流用して使用しているのでこのあたりが臭いとは思うのですが・・

コード:

public class MainRenderer implements Renderer {

	private Context context;
	Sprite testSprite = new Sprite();
	
	public MainRenderer(Context _context){
		context = _context;
	}
	
	@Override
	public void onDrawFrame(GL10 gl) {
		
		 // 画面を塗りつぶす
        gl.glClearColor(0.f, 0.5f, 0.f, 1.f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();

		testSprite.draw(gl);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		
//		// GLで利用する領域を設定
//        gl.glViewport(0, 0, width, height);
//
//        float ratio = (float) height / width;
//        gl.glMatrixMode(GL10.GL_PROJECTION);
//        gl.glLoadIdentity();
//
//        // 正射影モードで座標系を設定
//        // 左上(-1.0,-ratio) 右下(1.0f,ratio)
//        gl.glOrthof(-1.0f, 1.0f, -ratio, ratio, 0.5f, -0.5f);
        
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        GLU.gluOrtho2D(gl, 0.0f, 32, 0.0f, 32);
	}
	
	@Override
	public void onSurfaceCreated(GL10 gl,javax.microedition.khronos.egl.EGLConfig config) {
		
		//背景色をクリア
		gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		//ディザを無効化
		gl.glDisable(GL10.GL_DITHER);
		gl.glEnable(GL10.GL_DEPTH_TEST);
		//テクスチャ機能ON
		gl.glEnable(GL10.GL_TEXTURE_2D);
		//透明可能に
		gl.glEnable(GL10.GL_ALPHA_TEST);
		//ブレンド可能に
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		
		gl.glDepthFunc(GL10.GL_LEQUAL);
		
		
		testSprite.setTexture(gl, context.getResources(), R.drawable.f03);
	}

}

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

Re: OpenGLでの画面の拡縮について

#5

投稿記事 by ISLe » 11年前

GL11Ext#glDrawTexfOESは射影変換を無視するみたいです。

奥兵

Re: OpenGLでの画面の拡縮について

#6

投稿記事 by 奥兵 » 11年前

ありがとうございます、glDrawTexfOESを代替する処理を探してみます。
代替する処理が見つかったら実験して報告させていただきます。

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

Re: OpenGLでの画面の拡縮について

#7

投稿記事 by ISLe » 11年前

VBO(頂点バッファオブジェクト)を使ってglDrawArraysで描画するのが良いと思います。
ネットで検索すれば解説記事がたくさん見付かります。

奥兵

Re: OpenGLでの画面の拡縮について

#8

投稿記事 by 奥兵 » 11年前

glDrawArraysでテクスチャを描画しているコードを見つけたのでそれを参考にテクスチャ描画用のクラスを作ったのですが、画面上のピクセルを指定して描画する部分で詰まってしまいました。
以前DirectXに手を出した時も同様の問題で一度詰まっってしまったので、その時の方法をあれやこれやと試したもののどうもうまく行きません。

コード:

public void draw( GL10 gl){
	    //-------------------------------------------------------------
	    //テクスチャ座標の位置とデータを指定
	    // 位置情報 uvは左上が(0,0)
	    // ※本当は左下が(0,0)だが画像が上下ひっくり返る為、左上が(0,0)と考える
	    float uv[] = {
	                0.0f, 0.0f,// !< 左上
	                0.0f, 1.0f,// !< 左下
	                1.0f, 0.0f,// !< 右上
	                1.0f, 1.0f,// !< 右下
	    };
	
	    // OpenGLESがVMとは違う領域で動作する為、
	    // 直接参照可能なメモリを用意し保存。
	    // Floatなので、要素数×4バイトを確保
	    ByteBuffer bbuv = ByteBuffer.allocateDirect(uv.length * 4);
	    // (Big or Little)エンディアンの呼び出し、および設定。
	    bbuv.order(ByteOrder.nativeOrder());
	    // Floatを書き込むための補助クラス
	    FloatBuffer fbuv = bbuv.asFloatBuffer();
	    // Bufferに配列を転送する
	    fbuv.put(uv);
	    // 書き込み位置を最初に戻す
	    fbuv.position(0);
	
	    // テクスチャバッファの成分を有効にする。
	    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
	    // 1.要素数uv 2つ
	    // 2.Bufferが格納されている型の指定
	    // 3.第一引数を読み込んだ後、読み込みをスキップする数
	    // 4.値が格納されているバッファの指定
	    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, fbuv);
	    //-------------------------------------------------------------
	    //-------------------------------------------------------------
	    // ! 位置情報
	    
	    float positions[] = {
	            // ! x y z
	            -1.0f, 1.0f, 0.0f, // !< 左上(uv一行目に対応)
	            -1.0f,-1.0f, 0.0f, // !< 左下(uv二行目に対応)
	             1.0f, 1.0f, 0.0f, // !< 右上(uv三行目に対応)
	             1.0f,-1.0f, 0.0f, // !< 右下(uv四行目に対応)
//	    		pos_x	, pos_y, 0.0f, // !< 左上(uv一行目に対応)
//	    		pos_x,pos_y - 1, 0.0f, // !< 左下(uv二行目に対応)
//	    		pos_x + 1, pos_y, 0.0f, // !< 右上(uv三行目に対応)
//	    		pos_x + 1,pos_y - 1, 0.0f, // !< 右下(uv四行目に対応)
	    		
	    };
	    
	    //////////////////
//	    gl.glOrthof(0f, 1776f, 1080f, 0f, -1.0f, 1.0f);
//	    gl.glMatrixMode(GL10.GL_MODELVIEW);
//	  gl.glPushMatrix();
//    gl.glLoadIdentity();
		//////////////////
	    
	    // ! OpenGLはビッグエンディアンではなく、CPUごとの
	    //ネイティブエンディアンで数値を伝える必要がある。
	    // ! そのためJavaヒープを直接的には扱えず、
	    //java.nio配下のクラスへ一度値を格納する必要がある。
	    ByteBuffer bb = ByteBuffer.allocateDirect(positions.length * 4);
	    bb.order(ByteOrder.nativeOrder());
	    FloatBuffer fb = bb.asFloatBuffer();
	    fb.put(positions);
	    fb.position(0);
	
	    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
	    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, fb);
	    // 1.モード(GL_TRIANGLE_STRIP:連続した三角形)
	    // 2.何番目の頂点から描画を行なうかを指定
	    // 3.いくつの頂点を利用するかを指定
	    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
	    //-------------------------------------------------------------
	    //1776 1080
	    //( x/(1080/2.0f)-1.0f, -y/(1776/2.0f)+1.0f, 1.0f )
	}

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

Re: OpenGLでの画面の拡縮について

#9

投稿記事 by ISLe » 11年前

奥兵 さんが書きました:glDrawArraysでテクスチャを描画しているコードを見つけたのでそれを参考にテクスチャ描画用のクラスを作ったのですが、画面上のピクセルを指定して描画する部分で詰まってしまいました。
gl.glViewport(0, 0, w, h);
GLU.gluOrtho2D(gl, 0.0f, w, h, 0.0f);
とした場合、デバイス画面の左上隅からの(0,0)-(w,h)を、(0,0)-(w,h)の座標(いわゆるピクセル座標)で指定して描画することになります。

同じ座標を指定しても、ビューポートと射影変換のパラメータによって描画される位置が変わります。

GLnn#glViewportはデバイス画面のどこを描画対象にするかを指定します。
GLU#gluOrtho2Dは描画対象範囲に対して左右上下端の座標を割り付けます。

奥兵

Re: OpenGLでの画面の拡縮について

#10

投稿記事 by 奥兵 » 11年前

ピクセル単位で描画できました。多謝です。
コピペでクラスのアウトラインを引っ張ってくるときに不必要なglOrthofを消すのを忘れていました。むしろ不必要ということが理解できていなかった感があります。

でもって次から次へとうまくいかないことばかり起こって悩ましいのですが、今度は描画したポリゴンが変に透けてしまいます。
まるでほつれた布みたいになっていますが、実行のたびにほつれ具合が変わります。更にテクスチャ画像の機首に当たる部分が縦方向に一周して後ろ側から少しはみ出してしまっています。

えっと、この掲示板の画像の貼り方がわからず、UPろだもほとんど使ったことがありませんで・・
http://pc.gban.jp/?p=55825.png
これでご覧いただけるでしょうか?

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

Re: OpenGLでの画面の拡縮について

#11

投稿記事 by ISLe » 11年前

奥兵 さんが書きました:でもって次から次へとうまくいかないことばかり起こって悩ましいのですが、今度は描画したポリゴンが変に透けてしまいます。
まるでほつれた布みたいになっていますが、実行のたびにほつれ具合が変わります。更にテクスチャ画像の機首に当たる部分が縦方向に一周して後ろ側から少しはみ出してしまっています。
ほつれはメモリ破壊系のバグっぽいですね。
引数に与えたバッファサイズと実際のサイズが異なっているとかそういった誤りはないでしょうか。

テクスチャが回り込むのは、テクスチャパラメータで適切にクランプするように設定すれば回避できると思います。

奥兵

Re: OpenGLでの画面の拡縮について

#12

投稿記事 by 奥兵 » 11年前

返事が遅くなって申し訳ないです。2日程体調を崩していまして。皆様もどうかお気をつけを。
それはさておき、あれやこれやと試してみたもののどうしてもほつれのような乱れが治らなかったので、シンプルに板ポリを表示するだけのサンプルを走らせてみましたが、それでもやはりほつれが起こってしまいました。

参考にしたサイトです
http://team-pag.interprism.co.jp/member ... og/?p=1247

コード:

public class TesPori {
	
	 private static final FloatBuffer makeFloatBuffer(float[] arr){
	        ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
	        bb.order(ByteOrder.nativeOrder());
	        FloatBuffer fb = bb.asFloatBuffer();
	        fb.put(arr);
	        fb.position(0);
	 
	        return fb;
	}
	 
	
	public void draw( GL10 gl){
		
		// 画面を塗りつぶす
        gl.glClearColor(0.f, 0.f, 1.f, 1.f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        
		 // 四角形の座標
        float[] vertices ={
                -0.5f, -0.5f,
                 0.5f, -0.5f,
                -0.5f, 0.5f,
                 0.5f, 0.5f,
        };

        FloatBuffer fb = makeFloatBuffer(vertices);
        
        
        // 四角形の描画
        gl.glVertexPointer(2, GL10.GL_FLOAT, 0, fb);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
		
	}
}
Rendererも殆ど参考サイトのほうからいじっておらず、DrawArraysではなくglDrawTexfOESを使った描画だと問題を起こさないので、こちらは大丈夫だと思うのですが。

コード:

package com.example.GLtest;

import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;

public class MainRenderer implements Renderer {

	private Context context;
	TesPori tesP = new TesPori();
	//TexbyArray test2 = new TexbyArray();
	
	public MainRenderer(Context _context){
		context = _context;
	}
	
	@Override
	public void onDrawFrame(GL10 gl) {
		
		// 画面を塗りつぶす
        gl.glClearColor(0.f, 0.5f, 0.f, 1.f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

		//test2.draw(gl);
        tesP.draw(gl);
	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		
		// GLで利用する領域を設定
        gl.glViewport(0, 0, width, height);
        
        float ratio = (float) height / width;
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
 
        gl.glOrthof(-1.0f, 1.0f, -ratio, ratio, 0.5f, -0.5f);// 通常の画面中央原点
//       GLU.gluOrtho2D(gl, 0.0f, width, height, 0.0f);// pixel指定
        
	}
	
	@Override
	public void onSurfaceCreated(GL10 gl,javax.microedition.khronos.egl.EGLConfig config) {
		
		//背景色をクリア
		gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		//ディザを無効化
		gl.glDisable(GL10.GL_DITHER);
		gl.glEnable(GL10.GL_DEPTH_TEST);
		//テクスチャ機能ON
		gl.glEnable(GL10.GL_TEXTURE_2D);
		//透明可能に
		gl.glEnable(GL10.GL_ALPHA_TEST);
		//ブレンド可能に
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		
		gl.glDepthFunc(GL10.GL_LEQUAL);
		
		//test2.setTexture(gl, context.getResources(), R.drawable.f03);
		 
	}

}


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

Re: OpenGLでの画面の拡縮について

#13

投稿記事 by ISLe » 11年前

GL_DEPTH_TESTを有効化しているのに、バッファをクリアしていないのがほつれの原因ではないでしょうか?

23行目を
gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
に変更してみてください。

必要なければGL_DEPTH_TESTは無効で良いかとも思いますが。

奥兵

Re: OpenGLでの画面の拡縮について

#14

投稿記事 by 奥兵 » 11年前

お教えいただいた部分を修正するときれいに描画できました。
そもそも深度テストもわからず、描画設定のあたりは定型文だろうと思って見過ごしていました。
ほんとうにありがとうございます。おかげでそれは美しい板ポリゴンを描画できました。

閉鎖

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