web-dev-qa-db-ja.com

libGDXプロジェクションマトリックスを理解する

過去数週間、私はlibGDXライブラリを学習しようとしてきました。特にゲーム開発に向けた最初の取り組みでは、カメラとビューポートの関係のシステムを理解するのが難しいと感じています。私が使用するように言われ、APIが言及しているコードの1行は、次のとおりです。

    batch.setProjectionMatrix(camera.combined);

4時間の調査にもかかわらず、このコードの機能を完全に理解することはできません。それがカメラが見ているバッチを「伝える」ことは私の基本的な理解です。私の理解力の欠如は憂うつで怒りです。誰かが私を助けてくれたら幸いです。コードスニペットのもう1つの問題は、いつ実装する必要があるのか​​(renderメソッド、createメソッドなど)がわからないことです。

21
user3059686

カメラで写真を撮ることを検討してください。例えば。スマートフォンのカメラを使って公園のベンチの写真を撮ります。そうすると、スマートフォンの画面に公園のベンチが表示されます。これは非常に明白に思えるかもしれませんが、これが何を含むのかを見てみましょう。

写真のベンチの位置は、写真を撮ったときに立っていた場所を基準にしています。言い換えれば、それはカメラに関連しています。通常のゲームでは、オブジェクトをオブジェクトに対して相対的に配置しません。代わりに、それらをゲームの世界に配置します。ゲームの世界とカメラの間の変換は、マトリックス(座標を変換するための数学的な方法)を使用して行われます。例えば。カメラを右に動かすと、ベンチが写真の左に移動します。これは、ビューマトリックスと呼ばれます。

写真上のベンチの正確な位置は、ベンチとカメラの間の距離にも依存します。少なくとも、3Dでは実行されます(2Dは非常に似ているので、読み続けてください)。遠くにあると小さくなり、カメラに近づくと大きくなります。これは透視投影と呼ばれます。正射影を使用することもできます。その場合、オブジェクトのサイズはカメラまでの距離に応じて変化しません。いずれにせよ、公園内のベンチの場所とサイズは、画面上のピクセル単位の場所とサイズに変換されます。例えば。ベンチは公園内で幅2メートルですが、写真では380ピクセルです。これは射影行列と呼ばれます。

_camera.combined_は、ビューと射影行列の組み合わせを表します。言い換えれば、ゲームの世界のどこに物事を画面に表示するかを説明します。

batch.setProjectionMatrix(cam.combined);を呼び出すと、その結合された行列を使用するようにバッチに指示します。値が変わるたびにそれを呼び出す必要があります。これは通常、resizeが呼び出されたとき、およびカメラを移動したり変更したりするときです。

不明な場合は、renderメソッドの先頭で呼び出すことができます。

23
Xoppa

他の答えは素晴らしいですが、クリックするのに役立つかもしれない別の説明方法を考えています。

通常、ゲームは「ワールドスペース」、つまり現実の世界に類似した座標系で扱います。線形代数では、2つの座標系間の関係を表す行列を点の座標に乗算することにより、空間内の点を1つの座標系から別の座標系に変換できます。

ビューマトリックスにポイントを掛けて、ワールドスペースからカメラスペース(カメラの視点)に変換します。射影行列は、ポイントをカメラ空間から画面空間(デバイスの画面の平らな2D長方形)に変換するために使用されます。 Libgdxのカメラでupdate()を呼び出すと、位置、方向、ビューポートサイズ、視野などの最新の変更がビューと投影マトリックスに適用され、シェーダーで使用できるようになります。

2Dでカメラ空間内のものを処理する必要はめったにないため、SpriteBatchは個別のビューマトリックスと投影マトリックスを必要としません。それらは、ワールド空間からスクリーン空間に直接変換する単一のマトリックスに組み合わせることができます。これは、カメラですでに自動的に行われているため、camera.combinedマトリックス。

SpriteBatchには、この投影行列にスプライトのすべての頂点を乗算するデフォルトの組み込みシェーダーがあり、フラットスクリーンに適切にマッピングされます。

カメラを移動したり、画面のサイズを変更したりするたびに、setProjectionMatrixを呼び出す必要があります。

3Dのものに使用されるモデル行列と呼ばれる3番目のタイプの行列があります。モデル行列は、世界空間におけるモデルの方向、スケール、および位置を記述します。したがって、モデル内の座標を掛けて、ローカル空間からワールド空間に移動します。

14
Tenfour04

たとえば、基本的な横スクロールゲームを考えてみましょう。プレーヤーが横に移動すると、カメラがパンして追随します。つまり、画面と世界は相互に関連して移動するため、オブジェクトが世界のどこにあるかは、必ずしも画面上の場所に対応しているとは限りません。

次に例を示します。画面が100px * 100pxの正方形であるとします(何らかの理由で)。オブジェクトを位置(50、0)に配置すると、画面の中央と下部に配置されます。ここで、プレーヤーを右に移動すると、画面全体がパンしてプレーヤーを追跡するとします。これは、前に配置したオブジェクトが画面上で左に移動している必要があることを意味します。つまり、実際には他の風景に対して移動しなかったため、世界ではまだ(50、0)にありますが、画面上のたとえば(10、0)に描画されるはずです。画面が見ている世界の変化。これは、「ワールドスペース」(オブジェクトがワールド内にある)と「スクリーンスペース」(オブジェクトが実際のディスプレイに描画される場所)の違いです。

SpriteBatchで描画しようとすると、デフォルトでは、ワールドスペース座標がスクリーンスペース座標と同じであると想定されます。「drawat(50、0)」と言うと、オブジェクトは次の場所に描画されます。画面上の(50、0)。カメラが動いても、常に画面の(50、0)に描画されるため、カメラがパンすると、オブジェクトは画面上の同じ場所に追従して固定されたままになります。

通常はそれを望まないので、SpriteBatch a 射影行列を指定します。これは、画面空間座標を世界空間座標に、またはその逆に変換する方法を指示する変換行列です。このように、バッチに「(50、0)で描画」と指示すると、カメラから取得したマトリックスを見て、カメラが移動したため、世界の(50、0)は実際には( 10、0)を画面に表示すると、スプライトが適切な場所に描画されます。

9
Caketray