4

Stack Overflow で OpenGL ES の 2D 選択の入門書を探していました。私は主に 3D に関する質問を目にします。

OpenGL ES を使用して、Android 4.0.3 で 2D タイルベースのレベル エディターを設計しています。レベル エディタでは、画面の中央に 2D の黄色の正方形のオブジェクトが配置されています。私が欲しかったのは、ユーザーがオブジェクトに触れたかどうかを検出することだけでした。

ここに画像の説明を入力

レベル エディターでは、重なっているタイルはありません。代わりに、MS ペイントのビットマップ イメージ内の隣接する 2 つのピクセルのように、横に並べて配置されます。私の目的は、レベル エディター内の各正方形オブジェクトのタッチ イベントを個別に検出することです。

オブジェクトは単純な頂点配列で作成され、GL_TRIANGLES を使用して 2 つの平らな直角三角形を描画します。ファイルなどからの操作やロードはありません。私が知っている唯一のことは、ユーザーが黄色の三角形のいずれかをタッチすると、両方の黄色の三角形が選択されるということです。

これをどのように行う必要があるかについて、誰かがヒントを提供できますか? 前もって感謝します。

編集:

これはdraw()機能です:

public void draw(GL10 gl) {
    gl.glPushMatrix();
    gl.glTranslatef(-(deltaX - translateX), (deltaY - translateY), 1f);
    gl.glColor4f(1f, 1f, 0f, 1f);
    //TODO: Move ClientState and MatrixStack outside of draw().
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertices);
    gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 6);
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glPopMatrix();
}

編集2:

まだいくつかの情報が不足しています。カメラを使っていますか?または、モデルのレンダリングの前に他のマトリックスをプッシュしますか? たとえば、正投影カメラを使用している場合、次のように画面座標 [x_screen, y_screen] を簡単に非投影にすることができます (y は類似しています)。

私はカメラを使用していませんが、おそらく正投影を使用しています。繰り返しますが、一般的な OpenGL 関数を使用しているだけなのでわかりません。多くのタイル (正方形の 2D オブジェクト) をさまざまな変換行列と統合することを計画しているため、行列のプッシュとポップを行います。2 つのタイルが同じ平行移動行列 M を持つことはありません。

透視投影は、2D に関して正投影と同じですか? 両者の間に違いは見られません。

GLSurfaceViewサーフェスが作成されたときの初期設定は次のとおりです ( を拡張し、 を実装するクラスGLSurfaceView.Renderer):

public void onSurfaceChanged(GL10 gl, int width, int height) {
    gl.glViewport(0, 0, width, height);
}

public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
    reset();
}
public void onDrawFrame(GL10 gl) {
    clearScreen(gl);
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    gl.glOrthof(0f, super.getWidth(), 0f, super.getHeight(), 1, -1);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    canvas.draw(gl);
}

private void clearScreen(GL10 gl) {
    gl.glClearColor(0.5f, 1f, 1f, 1f);
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
}
4

3 に答える 3

2

基本的なアプローチは次のとおりです。

  1. 「タッチ可能な」オブジェクトごとに境界ボックスを定義します。これは単なる長方形 (x、y、幅、高さ) である可能性があります。
  2. ワールド内のタイルを更新すると、そのバウンディング ボックスが更新されます (完全にワールド座標で)。
  3. ユーザーが画面に触れると、画面座標を世界座標に投影解除する必要があります
  4. 投影されていない点が境界ボックスと重なっているかどうかを確認します。

前の項目に関するいくつかのヒント。【編集済】

  • 1 と 2. タイルをレンダリングしている場所を追跡する必要があります。それらの位置とサイズを保存します。長方形は便利な構造です。あなたの例では、次のように計算できます。また、モデルが変更されたときに再計算する必要があります。それを Rectangle r と呼びましょう:

    r.x = yourTile.position.x -(deltaX - translateX)  
    r.y = yourTile.position.y -(deltaY - translateY)
    r.width= yourTile.width  //as there is no model scaling
    r.height = yourTile.height//
    
  • 3 - 正投影カメラを使用している場合は、次のように画面座標 [x_screen, y_screen] を簡単に投影解除できます (y は類似しています)。

    x_model = ((x_screen/GL_viewport_width) -0.5 )*camera.WIDTH + Camera.position.x
    
  • 4 - Rectangles ごとに [x_model; y_model] はその中にあります。

[2回目の編集]マトリックスを更新している途中で、位置がsurfaceView.width()/2、surfaceView.height()/2のカメラを使用していると考えることができます。画面上の 1 ピクセルを世界の 1 単位に一致させるため、何も投影解除する必要はありません。私の数式でその値を置き換えて、 x_screen = x_model - を取得できます (Java では Y が下向きに、GL では上向きに成長するため、タッチ イベントの Y コンポーネントを反転する必要があります)。

最後の言葉。ユーザーがポイント [x,y] に触れた場合、[x, screenHeight-y]* がいくつかの長方形に当たるかどうかを確認し、完了です。デバッグを行い、接触点をログに記録して、それらが期待どおりかどうかを確認します。長方形を生成し、それらが画面に表示されるものと一致するかどうかを確認します。次に、点が長方形の内側にあるかどうかを確認します。

カメラを画面のサイズに設定しないでください。デバイスによってアプリの外観が大きく異なるためです。これはそれ自体のトピックであるため、これ以上は説明しませんが、画面サイズとは関係なく、ワールド単位でモデルを定義することを検討してください。話が脱線してしまいましたが、知っておくべきことをよく理解していただけたでしょうか。

*私があなたに言ったフリッピング。PS: 正投影を使用してください (遠近法の使用はより複雑になります)。

于 2012-12-19T12:34:45.473 に答える
1

あなたの質問に対する 2 番目の回答を投稿させてください。これは完全に高レベル/哲学的です。ばかげた、役に立たない答えかもしれませんが、コンピューターグラフィックスに慣れていない人が「グラフィックモード」に心を変えるのに役立つことを願っています。

画面上で三角形を実際に選択することはできません。その正方形は 2 つの三角形ではありません。その正方形は、黄色のピクセルの集まりです。OpenGL はいくつかの頂点を取り、それらを接続し、処理し、画面上のいくつかのピクセルに色を付けます。グラフィックス パイプラインのある段階では、幾何学的情報さえも失われ、孤立したピクセルしかありません。これは、プリンターで紙に印刷された手紙に似ています。あなたは通常、紙からの情報を処理しません (わかりました、おそらくバーコード リーダーは :D)

図面をさらに処理する必要がある場合は、図面をモデル化し、補助データ構造を使用して自分で処理する必要があります。そのため、タイルをモデル化するために四角形を作成することをお勧めしました。オブジェクトの架空の「世界」を作成し、それらを画面にレンダリングします。ユーザーのタッチイベントは同じ世界に属していないため、画面座標を世界座標に「変換」する必要があります。次に、世界で何かを変更し (ユーザーが指をドラッグしてオブジェクトを移動する必要がある場合があります)、再び OpenGL に世界を画面にレンダリングするように指示します。

ビューではなく、モデルを操作する必要があります。メッシュはビューに関するものなので、モデル情報と混合するべきではありません。両方を分離することをお勧めします。(専門家が私を訂正してください、私はかなりのグラフィック愛好家です)

于 2012-12-19T20:20:27.787 に答える
0

LibGDXをチェックアウトしましたか?

OpenGLESを使用する際の作業が非常に簡単になります。

于 2012-12-19T11:36:27.460 に答える