GLViewportの混乱


9

誰かがGLViewportを理解し、サイズを変更するとどうなるかを理解してくれることを願っています

これは私の混乱を示します。

ここに画像の説明を入力してください

だから、ここで私は画面の真ん中にクワッドをスタックしています。GLViewportをデバイスの幅と高さに一致させると、最初の(左側の)画像が表示されます。まさに私が期待するもの。

  • デバイスの解像度、2560 x 1600
  • ビューポート解像度2560 x 1600
  • クワッドサイズ200 x 200(注、上の画像は実物大ではありません!!! :-))
  • 四角形、正方形として表示

さて、2枚目(右)の写真です...

  • デバイスの解像度、2560 x 1600
  • ビューポート解像度2560 x 1200(および垂直方向中央)
  • クワッドサイズ(200、200)
  • 四角形、長方形として表示

私の質問は、四角形が四角形ではなく四角形として表示されているのはなぜですか?私のクワッドが200 x 200ピクセルであることをログに記録して確認しました-物理ピクセルのサイズは確かに同じですか?変更することはできません。ここで何が起こっているのでしょうか?

私は(明らかに間違って)ビューポートを拡大縮小したとき、文字通りピクセルを切り落としたと考えました。

これがどのように機能するかを誰かが説明できれば幸いです。

編集する

現在、私はビューポートを次のように設定しています:

width = (int) Math.min(deviceWidth, deviceHeight * 1.702127659574468);    
height = (int) Math.min(deviceHeight, deviceWidth / 1.702127659574468);

ratio = width / height;
GLES20.glViewport(offsetX, offsetY, width, height);

Matrix.orthoM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

offsetXとoffsetYは、レターボックスがある場合にビューポートが中央に配置されるようにするためのものです。


垂直ピクセルを1600から1200に変更するときに、投影マトリックスとビューポートを変更しましたか?(あなたがする必要があります)
bcrist 14

こんにちは@bcrist、私の編集を見て、ビューポートの設定方法を示してください。同じ数のピクセル(たとえば、50 x 50、または100 x 100)を持つ私が描くすべてのものは、「引き伸ばされた」ものを描いています-何かアイデアはありますか?!
BungleBonce 2014年

ところで、のglScissor代わりにを使用するとglViewport、レンダリングされる場所を変更せずに、単にピクセルを切り取ります。 glViewportトリミングするのではなく、元の画像のサイズを変更するように動作します。それがあなたの箱を押しつぶす理由です。
ネイサンリード

@NathanReedのおかげで、私はまだ本当に混乱しています。私が持っているのはこれです:画面全体を占めるビューポート。元のデバイスの比率を維持するようにスケーリングされたシザーボックス(シザーボックスにゲームを表示し、フィラーの外側にこれを描画できるようにする)、すべてが(垂直方向に)引き伸ばされて表示されるため、幅よりも長くなります。何が悪いのですか?
BungleBonce 2014年

うーん。はさみの四角形は、画像のアスペクト比やスケーリングについて何も変更しないでください。はさみがなくても正しく見える場合は、はさみを有効にするだけで(同じビューポート、投影行列などを維持するだけで)、画像が切り取られます。
ネイサンリード

回答:


11

何が起こっているのかを理解するには、レンダリングパイプラインを理解する必要があります。

ジオメトリ(クワッド)は、最初はワールド空間で定義されています。これをグローバル座標系と考えてください。頂点シェーダーの内部では、これらは-1から1までのすべてが画面に描画されるように定義された仮想座標系である正規化デバイス座標(NDC)に変換されます。NDCはXとYで-1から1の範囲であり、デバイスのアスペクト比と解像度から完全に独立していることに注意してください。ワールド空間からNDCへのこの変換は、モデル、ビュー、および射影行列によって行われます(単純な形式では、すべての1つの行列またはジオメトリがNDCで最初に定義されていました!)。

ラスタライズユニットは、ラスタをどこにどのくらい大きくするかを知る必要があります。これは、glViewport呼び出しで定義するものです。開始する場所は最初の2つのパラメーター、サイズは2番目の2つです。次に、ハードウェアは単純なスケールとシフトによってNDCからピクセル座標に変換します。これが、例に表示されているもの、つまりY軸のスケールです。

したがって、クワッドが正しいアスペクト比でレンダリングされるようにするには、予測マトリックスを調整して、glViewport呼び出しの予想されるアスペクト比を含める必要があります。


こんにちは、@ロバート、これに感謝します。これを実装するのに苦労しています。投影行列を設定する例を挙げてください。ありがとう!
BungleBonce 2014年

4
こんにちはuser22241です。これを行うOpenGLコマンドはありません。独自にマトリックス(フロートの4 x 4配列)を定義し、それらをユニフォームとして頂点シェーダーに提供する必要があります。必要な投影法(遠近法、直交法)は、何をしたいかによって異なります。3D投影の数学的概念が初めての場合は、OpenGL ESと同じように機能するコアプロファイルを教えるOpenGLチュートリアルを調べてみてください。
Robert

@BungleBonceコアプロファイルにはOpenGLコマンドがありませんglFrustumが、これらの関数によって構築される正確な行列をリストするのような廃止されたコマンドのドキュメントをいつでも見ることができます。あなたが望むかもしれない他の一般的な射影行列はによって作成されましたglOrtho。これらのコマンドはすべて廃止されていますが、それらに関するドキュメントは、いくつかの事前導出された数学の優れたソースです。
Ruslan

0

glViewportの呼び出しでは、幅と高さのピクセル数を少なく指定しています。射影行列はピクセルで定義されます。そのため、glViewportの呼び出し後に新しい射影行列を計算する必要があります。


こんにちは@bogglez、回答ありがとうございます。ビューポートに使用しているコードを(最後に)表示するように質問を編集しました。私が使用しているのはglViewPortだけです-これを行うには間違った方法ですか?回答の中であなたが意味することの例を示していただけませんか?ありがとう。
BungleBonce 2014年

これを読んでください:songho.ca/opengl/gl_projectionmatrix.html 2Dの場合は正射影行列、3Dの場合は遠近法行列が必要です。最新のOpenGLを使用する場合は、シェーダーにマトリックスを提供します。固定グラフィックスパイプラインで非推奨のOpenGLを使用する場合は、glLoadMatrix、glFrustumなどの関数を使用して、射影行列を計算します。ユーティリティライブラリGLUには、それを支援するための関数gluPerspective(opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml)とgluOrtho2D(opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml)があります。
bogglez 14年

0

最初の写真:

  1. 射影行列を作成しています。たとえば、使用されるパラメーターは、Left1、Right1、Bottom1、Top1、Near1、Far1です。ここで、Aspect_Ratio_1A =(Right1-Left1)/(Top1-Bottom1);

  2. 次に、ビューポートの変換を行っています。たとえば、使用されるパラメーターはWidth1、Height1です。(簡単にするために、シフトパラメーターについては言及していません)。ここでは、Aspect_Ratio_1B = Width1 / Height1;

2番目の画像の場合:

  1. 以前と同じパラメーターで同じ射影行列を作成しています。つまり、Aspect_Ratio_2A = Aspect_Ratio_1A;

  2. 今回は、ビューポート変換に異なるパラメーターがあります:Width2とHeight2。ここで、Aspect_Ratio_2B = Width2 / Height2。

Aspect_Ratio_1BとAspect_Ratio_2Bは異なることに注意してください。具体的には次のとおりです。

Aspect_Ratio_1B = 2560/1600 = 1.6 Aspect_Ratio_2B = 2560/1200 = 2.13

したがって、2番目のケースで行っていることを要約すると、次のようになります。

Aspect_Ratio_2Aを使用して画像を平面に投影し、ユーザーに表示する前に、Aspect_Ratio_2Bにスケーリングします。他のユーザーから、Aspect_Ratio_2A = Aspect_Ratio_2Bとなるように射影行列を修正するように依頼されています。

ロバートのコメントを数回読んで、理解を深めることもできます。

また、2番目の画像の赤い四角形が画面に描画されたときに200 x 200ピクセルのサイズであることにも同意できません。ご存知のように、ピクセルは正方形です。四角形の辺が他より長い場合、長い辺の方が確実に描画されるピクセルが多くなります。個人的には、ロギングとは何なのかわかりませんが、画面のピクセルサイズが返されない可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.