質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

OpenGL ES

携帯電話のような組込み機器のためにデザインされたOpenGLのサブセットです。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Q&A

解決済

1回答

3450閲覧

OpenGL:動的に変化するビューポートのサイズに対して相対的にスクリーンタッチした座標を変換したい

norton

総合スコア11

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

OpenGL ES

携帯電話のような組込み機器のためにデザインされたOpenGLのサブセットです。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

0グッド

0クリップ

投稿2015/12/16 05:24

編集2015/12/16 16:00

現在、Java+OpenGL ES1.0を使用してAndroid用のゲームを制作しています。

ゲームのメニューボタンなどをタッチすると、そのボタンが存在している座標内か判定して、そうであればそれぞれ適切な処理を行わせていました。
しかし、下記の対応をしたところ、表題の現象が起きて困っています。

描画処理は全てOpenGLを使用しています。
元々、スクリーンサイズいっぱいのサイズのビューポートを設定して、レンダリングを行っていたのですが、
Androidの多様なデバイスのアスペクト比でも描画がくずれないように、ベースのアスペクト比を決めて、
アプリを起動すると、可能な限り画面サイズいっぱいまで拡げた、ベースのアスペクト比を保ったサイズのビューポートを設定して、その中でレンダリングを行い、
スクリーンの余っている部分は何も描画しないように対応しました(真っ暗)。

例えば、16:9(height:width)のアスペクト比をベースとしたとすると、
16:11のデバイスだと、縦方向には画面いっぱいビューポートが埋まっていて、
横方向は左部分に1、右部分に1、何も描画していないスペースがある状態です。

18:9のデバイスだと、横方向は画面いっぱいのビューポートで埋まっていて、
縦方向に上下1づつ、何も描画していないスペースがある状態です。

このようにしたところ、
ベースのアスペクト比と異なるデバイスの場合、ボタンの描画位置がスクリーンの内側に移動していて、
画面いっぱいにビューポートを設定していたときに表示されていたボタンの位置をタッチすると衝突を検出して、
実際に表示しているボタンの上をタッチしても反応しなくなりました。
イメージ説明

なので、タッチした座標を実際の位置よりも外側の位置へ変換するようにしたいと考えたのですが、うまくいきません。。

以下に抜粋したコード・やってみたことを記載しています。
解決策をご教示願えますでしょうか。

Java

1 2コード 3//定数クラス. 4public class Constants { 5 public static final float ASPECT = 1.575f; //ベースのアスペクト比. 6 public static final float BASE_FRUSTUM_WIDTH = 224; //ベースの視錐台の幅. 7 public static final float BASE_FRUSTUM_HEIGHT = BASE_FRUSTUM_WIDTH * ASPECT; //ベースの視錐台の高さ. 8} 9 10//ベクトルクラス. 11public class Vector { 12 float x; 13 float y; 14 15 public Vector(float x, float y) { 16 this.x = x; 17 this.y = y; 18 } 19 20 public Vector add(Vector other) { 21 this.x += other.x; 22 this.y += other.y; 23 return this; 24 } 25 26 public Vector sub(float x, float y) { 27 this.x -= x; 28 this.y -= y; 29 return this; 30 } 31} 32 33//////////////////////////////////////////////////////////////////////////////// 34// クラス名:Camera2D 35// 内 容:2Dレンダリング用カメラクラス. 36//////////////////////////////////////////////////////////////////////////////// 37 public class Camera2D { 38 public final Vector position; //カメラの座標. 39 public float zoom; //カメラのズーム値. 40 int screenWidth; //デバイスのスクリーンの幅. 41 int screenHeight; //デバイスのスクリーンの高さ. 42 float viewportWidth; //ビューポートの幅. 43 float viewportHeight; //ビューポートの高さ. 44 45//////////////////////////////////////////////////////////////////////////////// 46// メソッド名:Camera2D(コンストラクタ) 47// 内 容:カメラの位置、視錐台の幅と高さ、およびズーム倍率をメンバとして格納する. 48// カメラの中心がスクリーンの背景の中心になるように設定する. 49//////////////////////////////////////////////////////////////////////////////// 50 public Camera2D(int screenWidth, int screenHeight) { 51 this.screenWidth = screenWidth; 52 this.screenHeight = screenHeight; 53 //カメラの位置を視錐台の中心に初期化. 54 this.position = new Vector(BASE_FRUSTUM_WIDTH / 2, BASE_FRUSTUM_HEIGHT / 2); 55 this.zoom = 1.0f; //ズーム倍率. 56 57 //ベースのアスペクト比のままスクリーンいっぱいにビューポートを拡げるための、倍率を求める. 58 float tempWidth = screenWidth / BASE_FRUSTUM_WIDTH; 59 float tempHeight = screenHeight / BASE_FRUSTUM_HEIGHT; 60 float magnification; 61 if(tempWidth > tempHeight) { 62 magnification = tempHeight; 63 } else { 64 magnification = tempWidth; 65 } 66 //ビューポートの幅・高さを格納する. 67 this.viewportWidth = magnification * BASE_FRUSTUM_WIDTH; 68 this.viewportHeight = magnification * BASE_FRUSTUM_HEIGHT; 69 } 70 71//////////////////////////////////////////////////////////////////////////////// 72// メソッド名:setViewportAndMatrices 73// 内 容:ビューポートと視錐台を設定する. 74//////////////////////////////////////////////////////////////////////////////// 75 public void setViewportAndMatrices(GL10 gl) { 76 77//delete >>> 78 //スクリーン全体を覆うようにビューポートを設定する. 79// gl.glViewport(0, 0, screenWidth, screenHeight); 80//delete <<< 81//add >>> 82 //スクリーンの中心にビューポートを設定する. 83 int startPosX = (screenWidth / 2) - (int)(viewportWidth / 2); 84 int startPosY = (screenHeight / 2) - (int)(viewportHeight / 2); 85 int endPosX = (int)viewportWidth; 86 int endPosY = (int)viewportHeight; 87 gl.glViewport(startPosX, startPosY, endPosX, endPosY); 88//add <<< 89 //OpenGL ESに行列を投影行列に変更するよう指定. 90 gl.glMatrixMode(GL10.GL_PROJECTION); 91 gl.glLoadIdentity(); 92 //指定した視錐台の幅と高さにズーム値を適用させた幅と高さを、カメラ中心位置から増減させたサイズの視錐台を設定する. 93 gl.glOrthof(position.x - BASE_FRUSTUM_WIDTH * zoom / 2, 94 position.x + BASE_FRUSTUM_WIDTH * zoom / 2, 95 position.y - BASE_FRUSTUM_HEIGHT * zoom / 2, 96 position.y + BASE_FRUSTUM_HEIGHT * zoom / 2, 1, -1); 97 gl.glMatrixMode(GL10.GL_MODELVIEW); 98 gl.glLoadIdentity(); 99 } 100 101//////////////////////////////////////////////////////////////////////////////// 102// メソッド名:touchToWorld 103// 内 容:タッチ座標が含まれたVectorインスタンスを受け取り、ベクトルをワールド座標に変換する. 104//////////////////////////////////////////////////////////////////////////////// 105 public void touchToWorld(Vector touch) { 106 //////////////////////////////////////////////////////////// 107 //////// タッチしたスクリーン座標をワールド座標に変換する. 108 //タッチしたポイントのx,y座標をスクリーンの幅と高さで割ることで、0〜1の範囲に正規化する. 109 //次に視錐台の幅と高さを掛けることで、ワールド座標として表される.この時、zoom値も掛け, 110 //ズームが適用されたワールド座標として表される. 111 //スクリーンは左上原点だが、OpenGLESフレームバッファの原点を左下と想定するのでY軸を反転させる. 112 touch.x = (touch.x / screenWidth) * BASE_FRUSTUM_WIDTH * zoom; 113 touch.y = (1 - touch.y / screenHeight) * BASE_FRUSTUM_HEIGHT * zoom; 114 //ズームが適用されたワールド座標上での適切なタッチ座標に変換する. 115 touch.add(position).sub(BASE_FRUSTUM_WIDTH * zoom / 2, BASE_FRUSTUM_HEIGHT * zoom / 2); 116 117 //////////////////////////////////////////////////////////// 118 //////// 以下、やってみたけどうまくいきませんでした。。 119 120 //////// ビューポートサイズとスクリーンサイズが異なる場合は、その差分タッチ座標をずらす. 121 float calX; 122 float calY; 123 //ワールド座標に変換されたタッチ座標から視錐台の中心座標を引いて、中心からのベクトルを求める. 124 calX = touch.x - (BASE_FRUSTUM_WIDTH / 2); 125 calY = touch.y - (BASE_FRUSTUM_HEIGHT / 2); 126 //次にビューポートの中心座標に上で求めた中心座標からのベクトルを足して、ビューポート上の視錐台の座標と同じ位置を求める. 127 calX += (viewportWidth / 2); 128 calY += (viewportHeight / 2); 129 //最後に視錐台サイズ/ビューポートサイズで求めた倍率を上記で求めたベクトルに掛けた値をタッチ座標とする. 130 touch.x = calX * (BASE_FRUSTUM_WIDTH / viewportWidth); 131 touch.y = calY * (BASE_FRUSTUM_HEIGHT / viewportHeight); 132 } 133 134 135 136 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

色々やってみたところ、自己解決しました。
以下のとおり修正して対応しました。

Java

1コード 2//定数クラス. 3public class Constants { 4 public static final float ASPECT = 1.575f; //ベースのアスペクト比. 5 public static final float BASE_FRUSTUM_WIDTH = 224; //ベースの視錐台の幅. 6 public static final float BASE_FRUSTUM_HEIGHT = BASE_FRUSTUM_WIDTH * ASPECT; //ベースの視錐台の高さ. 7} 8 9//ベクトルクラス. 10public class Vector { 11 float x; 12 float y; 13 14 public Vector(float x, float y) { 15 this.x = x; 16 this.y = y; 17 } 18 19 public Vector add(Vector other) { 20 this.x += other.x; 21 this.y += other.y; 22 return this; 23 } 24 25 public Vector sub(float x, float y) { 26 this.x -= x; 27 this.y -= y; 28 return this; 29 } 30} 31 32//////////////////////////////////////////////////////////////////////////////// 33// クラス名:Camera2D 34// 内 容:2Dレンダリング用カメラクラス. 35//////////////////////////////////////////////////////////////////////////////// 36public class Camera2D { 37 public final Vector position; //カメラの座標. 38 public float zoom; //カメラのズーム値. 39 int screenWidth; //デバイスのスクリーンの幅. 40 int screenHeight; //デバイスのスクリーンの高さ. 41 float viewportWidth; //ビューポートの幅. 42 float viewportHeight; //ビューポートの高さ. 43 float magnification; //視錐台をスクリーンいっぱいに拡げるための倍率. add. 44 45//////////////////////////////////////////////////////////////////////////////// 46// メソッド名:Camera2D(コンストラクタ) 47// 内 容:カメラの位置、視錐台の幅と高さ、およびズーム倍率をメンバとして格納する. 48// カメラの中心がスクリーンの背景の中心になるように設定する. 49//////////////////////////////////////////////////////////////////////////////// 50 public Camera2D(int screenWidth, int screenHeight) { 51 this.screenWidth = screenWidth; 52 this.screenHeight = screenHeight; 53 //カメラの位置を視錐台の中心に初期化. 54 this.position = new Vector(BASE_FRUSTUM_WIDTH / 2, BASE_FRUSTUM_HEIGHT / 2); 55 this.zoom = 1.0f; //ズーム倍率. 56 57 //ベースのアスペクト比のままスクリーンいっぱいにビューポートを拡げるための、倍率を求める. 58 float tempWidth = screenWidth / BASE_FRUSTUM_WIDTH; 59 float tempHeight = screenHeight / BASE_FRUSTUM_HEIGHT; 60// float magnification; delete. 61 if(tempWidth > tempHeight) { 62 magnification = tempHeight; 63 } else { 64 magnification = tempWidth; 65 } 66 //ビューポートの幅・高さを格納する. 67 this.viewportWidth = magnification * BASE_FRUSTUM_WIDTH; 68 this.viewportHeight = magnification * BASE_FRUSTUM_HEIGHT; 69 } 70 71//////////////////////////////////////////////////////////////////////////////// 72// メソッド名:setViewportAndMatrices 73// 内 容:ビューポートと視錐台を設定する. 74//////////////////////////////////////////////////////////////////////////////// 75 public void setViewportAndMatrices(GL10 gl) { 76 77//delete >>> 78 //スクリーン全体を覆うようにビューポートを設定する. 79// gl.glViewport(0, 0, screenWidth, screenHeight); 80//delete <<< 81//add >>> 82 //スクリーンの中心にビューポートを設定する. 83 int startPosX = (screenWidth / 2) - (int)(viewportWidth / 2); 84 int startPosY = (screenHeight / 2) - (int)(viewportHeight / 2); 85 int endPosX = (int)viewportWidth; 86 int endPosY = (int)viewportHeight; 87 gl.glViewport(startPosX, startPosY, endPosX, endPosY); 88//add <<< 89 //OpenGL ESに行列を投影行列に変更するよう指定. 90 gl.glMatrixMode(GL10.GL_PROJECTION); 91 gl.glLoadIdentity(); 92 //指定した視錐台の幅と高さにズーム値を適用させた幅と高さを、カメラ中心位置から増減させたサイズの視錐台を設定する. 93 gl.glOrthof(position.x - BASE_FRUSTUM_WIDTH * zoom / 2, 94 position.x + BASE_FRUSTUM_WIDTH * zoom / 2, 95 position.y - BASE_FRUSTUM_HEIGHT * zoom / 2, 96 position.y + BASE_FRUSTUM_HEIGHT * zoom / 2, 1, -1); 97 gl.glMatrixMode(GL10.GL_MODELVIEW); 98 gl.glLoadIdentity(); 99 } 100 101//////////////////////////////////////////////////////////////////////////////// 102// メソッド名:touchToWorld 103// 内 容:タッチ座標が含まれたVectorインスタンスを受け取り、ベクトルをワールド座標に変換する. 104//////////////////////////////////////////////////////////////////////////////// 105 public void touchToWorld(Vector touch) { 106 //////////////////////////////////////////////////////////// 107 //////// タッチしたスクリーン座標をワールド座標に変換する. 108//delete >>> 109 //タッチしたポイントのx,y座標をスクリーンの幅と高さで割ることで、0〜1の範囲に正規化する. 110 //次に視錐台の幅と高さを掛けることで、ワールド座標として表される.この時、zoom値も掛け, 111 //ズームが適用されたワールド座標として表される. 112 //スクリーンは左上原点だが、OpenGLESフレームバッファの原点を左下と想定するのでY軸を反転させる. 113// touch.x = (touch.x / screenWidth) * BASE_FRUSTUM_WIDTH * zoom; 114// touch.y = (1 - touch.y / screenHeight) * BASE_FRUSTUM_HEIGHT * zoom; 115// //ズームが適用されたワールド座標上での適切なタッチ座標に変換する. 116// touch.add(position).sub(BASE_FRUSTUM_WIDTH * zoom / 2, BASE_FRUSTUM_HEIGHT * zoom / 2); 117//delete <<< 118 //add >>> 119 float diffWidthViewportAndFrustum = (screenWidth - viewportWidth) / 2; 120 float diffHeightViewportAndFrustum = (screenHeight - viewportHeight) / 2; 121 122 touch.x = (touch.x / viewportWidth) * BASE_FRUSTUM_WIDTH * zoom; 123 touch.y = (1 - touch.y / viewportHeight) * BASE_FRUSTUM_HEIGHT * zoom; 124 //ズームが適用されたワールド座標上での適切なタッチ座標に変換する. 125 touch.add(position).sub(BASE_FRUSTUM_WIDTH * zoom / 2, BASE_FRUSTUM_HEIGHT * zoom / 2); 126 touch.add(-(diffWidthViewportAndFrustum / magnification * zoom), (diffHeightViewportAndFrustum / magnification * zoom)); 127 //add <<< 128 } 129}

投稿2015/12/16 20:01

編集2015/12/17 18:33
norton

総合スコア11

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問