9. 変換

9.001 変換のことが解りません。どこでマトリックスについて多くのことを学ぶことができますか?

基本的な行列数学およびリニアの代数学の完全な説明は、このFAQの範囲を越えてあります。 これらの概念は合衆国の高校数学クラスにおいて教えられます。

もし基本を理解するけれども、ただ、混同されて(経験豊かのためのさえ共通の問題!)ようになるならば、行列概念のスティーブベーカーのレビューおよびオイラーの彼の記事を通じて角度を読んでください。

基本的なベクトル、行列、および四つ一組操作を実行するためのDelphiコードは、ここで見つけられえます

9.005 OpenGL のマトリックスは行メジャーですか列メジャーですか?

目的をプログラミングするために、OpenGL行列は、メモリーにおいて接触して広げられた基本のベクトルを持つ16値配列です。 翻訳コンポーネントは、16要素行列の13番目、14番目、および15番目の要素を占めます。

カラム大手で、notational会議が列大手です。 カラム主要な行列によるポスト増加が列主要な行列によって前増加するのと同じ結果を引き起こすことに注意してください。 OpenGL指定およびOpenGL参照マニュアル両方はカラム主要な表記法を使います。 それがはっきりと述べられる限りどのような表記法でも使うことができます。

悲しげに、スペックと青い本のカラム主要なフォーマットの使用が、OpenGLプログラミングコミュニティでの無限の混乱を結果として生じました。 カラム主要な表記法は、プログラマーが予期するようにメモリーにおいて行列が広げられないことを示唆します。

主題のUsetnet投稿の要約はここで見つけられえます

9.010 OpenGL 座標の単位は何ですか?

短い答え: それらがそうであってほしい何でも。

幾何学データベースの内容に依存するので、アプリケーションが1つのOpenGL同等ユニットを間について1ミリメートルまたは1パーセクまたは何とでも等しいとみなすことが便利であるかもしれません(または、より大きいか、またはより小さい)。

OpenGLは、また、あなたに、異なる値の座標によって幾何学を指定させます。 例えば、モデル キロメートルに飛び回るセンチメートル、メートルのその機体、および世界の飛行機のコントロール のためにそれが便利なのを発見するかもしれません。 OpenGLのModelView行列は、その時同じ目同等スペースにこれらの種々の座標系を縮尺できます。

眺めの適切なフィールド、およびzNearzFarを適切な範囲で飛行機を切り取らせ続けることによって見物人を適切な距離に引き留めるイメージを提供するために投射とModelView行列が構成されることを保証することが、アプリケーションの責任です。 例えばミクロンスケールの分子を表示するアプリケーションは、たぶん、10フィートの距離で眺めの60度フィールドによってビューアを置きたくありません。

9.011 座標はどのように変換されますか?異なる座標系ではどう違いますか?

オブジェクト座標は、目座標を生み出すために、ModelView行列により変換されます。

目座標は、クリップ座標を生み出すために、投射行列により変換されます。

座標X、Yを切り取ってください。Zは、標準化機器座標を生み出すために、クリップ座標Wにより分割されます。

標準化された機器座標は、ウィンドウ座標を生み出すために、ビューポートパラメータによりサイズ変更されて、翻訳されます。

オブジェクト座標はすり傷です 調和する 呼び出しによってglVertex*()またはglVertexPointer()にOpenGLに服従する 。 それらは、オブジェクト、または与えたい他の幾何学の座標を表しています。

多くのプログラマーは世界座標系を使います。 しばしばオブジェクトの模型が1つの座標系で作られて、そして、世界に測量されて、翻訳されて、回転する 構成しています。 世界座標は、ModelView行列に蓄えられた模型製作変化によってオブジェクト座標を変換することに起因しています。 しかし、OpenGLは世界座標の概念を全然持っていません。 世界座標は純粋にアプリケーション構成物です。

目座標は、ModelView行列によってオブジェクト座標を変換することに起因しています。 ModelView行列は、ネガティブなZ軸と位置合わせされた眺め方向によってビューアを起源に置く模型製作と展望変化を含んでいます。

クリップは投射行列によって変換目座標から結果を調整します。 同等なスペース範囲をそれ- W から切り取ってくださいc Wにc 合計3つの斧 where W においてcクリップ座標W価値です。 OpenGLはこの範囲の外ですべての座標を切り取ります。

クリップ座標において実行されたパースペクティブ部門は、標準化機器座標 合計3つの斧で-1から1までの範囲 を作り出します。

ウィンドウ座標は、ビューポートによって標準化機器座標をサイズ変更することと翻訳することに起因しています。 glViewport()とglDepthRange()へのパラメータはこの変化をコントロールします。 ビューポートによってすることができます マップ ウィンドウと深さバッファのどのような位置への標準化機器座標立方体でも 。

詳細については、OpenGL指定、図2.6を見てください。

9.020 シーンの一つのオブジェクトだけを変形させる、または各オブジェクトを変形させるにはどのようにしたら良いですか?

OpenGLは行列スタックをこの目的に特に提供します。 このケースにおいて、ModelView行列スタックを使ってください。

典型的なOpenGLアプリケーションは、最初、行列モードを呼び出しにglMatrixMode(GL_MODELVIEW)に設定し、展望変化をロードし、たぶん、gluLookAt()でgluLookAt().More情報への呼び出しのため入手可能です

そして、コードは、呼び出しによって表現をglPushMatrix()とglPopMatrix()に巻きつけてそれ自身の変化によって個々のオブジェクトを場面に表現します。 例えば:

glPushMatrix();
glRotatef(90.、1.、0.、および0。);
gluCylinder(クワタ、1、1、2、36、および12);
glPopMatrix();

上記のコードは、X-軸のまわりの90度を、回転したシリンダに与えます。 ModelView行列は、glPopMatrix()呼び出しの後にその前の価値に回復されます。 同様な呼び出し連鎖は次のオブジェクトを場面に表現することができます。

9.030 三次元描画の上に二次元で描くにはどうしたら良いですか?

基本的な戦略は、コントロールを引くための2D投影を設定する必要があります。 3D与えだけでなく、またはオーバーレイ飛行機においてこれをすることができます。 もし3D表現だけでなくそうするならば、すべてのフレームの終わりでコントロールを再描画する必要があるでしょう(すぐ交換バッファの前で)。 もしオーバーレイ飛行機に引くならば、もしそれらをアップデートするならば、コントロールを再描画する必要があるだけです。

2D投影を設定するために、投射行列を変更する必要があります。 普通、投射を設定するので1つの世界同等ユニットが1つのスクリーンピクセルと次の通り等しいことが便利です:

glMatrixMode(GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (0、windowWidth、0、windowHeight);

gluOrtho2D()は-1から1までのZレンジをセットアップします。 従って、glVertex2*()のうちの1つを使う必要がある 幾何学を保証する機能は、zNearまたはzFarを切り取っている飛行機により切り取られません。

普通、違った形ですることが便利なのを発見するかもしれないけれども、引いている2Dがコントロールする時には、ModelView行列はアイデンティティに設定されます(例えば、インターリーブされた翻訳行列によって、繰り返されたコントロールを引くことができます)。

もし正確なpixelizationが必要ならば、下に示されるように小さい翻訳をModelView行列に入れたいでしょう:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glTranslatef (0.375、0.375、および0。);

もし3D深さ緩衝イメージだけでなく引いているならば、何とかして、2D幾何学を引く間深さテストを使用不可にする必要があるでしょう。 呼びかけることとglDisableであること(GL_DEPTH_TEST)またはglDepthFuncによって、これをすることができます(GL_ALWAYS)。 アプリケーションに依存することによって、2D表現を始める前に、深さ緩衝器も単にきれいにしてさしつかえありません。 最後に、最小のZ座標を持つ引いている合計2D幾何学が解決策でもあります。

2D投射が上記のように設立された後に、正常なOpenGLプリミティブをスクリーンに与えることができて、XYピクセルアドレスによってそれらの座標を指定します(OpenGL中心のスクリーンを使うことは、左下で調和します(0と0))。

9.040 OpenGL マトリックス変換を介さずに、ラスタライゼーションのための二次元座標を直接与えるにはどうしたら良いですか?

OpenGL行列変化を使用不可にするために、モードスイッチがありません。 もししかし、どちらまたは両方の行列でもアイデンティティに設定するならばglLoadIdentity()呼び出しのため、典型的OpenGLインプリメンテーションは、アイデンティティ変化が無-opであり、それに応じて作動すると知るように十分にインテリジェントです。

ラスタ化単のAPIとしてOpenGLを使うことについてのより詳細な情報は、OpenGLゲーム開発者のFAQにあります。

9.050 絶対座標と、相対座標を使う際の利点と欠点は何ですか?

いくつかのOpenGLアプリケーションが同じオブジェクトを単一の場面の多数所在地に表現する必要があるかもしれません。 OpenGLはあなたにこの2つの方法でさせます:

1) 「絶対座標」を使ってください。 それぞれ頂点のそれ自身のユニークなセットによって個々のオブジェクトの複数のコピーを維持してください。 要求された位置でオブジェクトをするために、ModelView行列を変更する必要はない。

2) 「相対座標」を使ってください。 ModelView行列スタック要求された変化を設定し、幾何学を送ることを押してオブジェクトのほんの1つのコピーを保持し、複数の時をそれに与えて、スタックを破裂させてください。 個々のオブジェクトのためにこれらのステップを繰り返してください。

などのでModelView行列に述べる一般的で、頻繁な変化において、アプリケーションの性能を否定的に詰め込むことができます。 もしたくさんの変化において個々の個々のプリミティブをModelView行列に包まないならば、OpenGLは幾何学をより速く処理できるでしょう。

しかし、時々、折り返している幾何学のメモリー貯金とこれを考量する必要があります。 高い近似によってドアノブを定義すると言おう 同じドアノブを持っているすべて 、200または300の三角形やあなたなどモデリングです それの50のドアを持つ家 。 たぶん、メモリーで、10-15K三角形を持つ使用絶対座標というよりもより、複数のユニークな変化行列によって単一のドアノブディスプレイリストを使うことが望ましい。

ケースバイケースの基礎において作るために必要な処理時間とメモリーの間のトレードオフが、 多くの計算問題 それとしてです。

9.060 同じ場面を複数の視点から見たように描くにはどのようにしたら良いですか?

glViewport()呼び出しを使って2つの眺めを同じウィンドウに引き入れることができます。 glViewport()を、望んでいるエリアに設定し 最初の眺め、場面の見方を設定する 、与えてください。 そして、glViewport()を2番目の眺めのためのエリアに設定し、また、場面の見方を設定し、与えてください。

いくつかの操作によりglViewportがSwapBuffersやglClear()など注意を払われないことに気づいている必要があります。 SwapBuffersはいつも全体のウィンドウを交換します。 しかし、シザー長方形を使って矩形のウィンドウにglClear()を制限できます。

アプリケーションは別個のウィンドウの種々の眺めを許すことができるだけです。 もしそうなら、2つの表現の間のMakeCurrent操作を実行する必要があります。 もし2つのウィンドウが文脈を共有するならば、上への説明のような場面の見方を変更する必要があります。 もしアプリケーションが個々のウィンドウのための別個の文脈を使うならば、これは必要ではないでしょう。

9.070 固定された座標系のシステムの中のローカル座標系のオブジェクトを変形させるにはどうしたら良いですか?

もしそのY軸のまわりのオブジェクトを回転させるならば、X-とZ-斧が、オブジェクトによって回転すると気付くでしょう。 これらの斧のうちの次の回転約1つは、オリジナルな軸ではなく、新しく変換された軸のまわりで回転します。 オブジェクトのローカルな座標系というよりも、しばしば、固定されている座標系での変化を実行することが望ましい。

OpenGLゲーム開発者のFAQは、この問題を解決することについて有益であるかもしれない回転を蓄えるために四つ一組を用いることについての情報を含んでいます。

問題の根原因は、OpenGL行列操作が行列スタックの上にポスト増加することであり、従って、変化をオブジェクトスペースに存在させます。 スクリーンスペース変化に影響するように、前増加する必要があります。 OpenGLはモードスイッチを行列増加の注文に提供しません。従って、手で前増加する必要があります。 アプリケーションは、個々のフレームの後で現在の行列を取り出してこれを実装できます。 アプリケーションはアイデンティティ行列だけでなく次のフレームのための新しい変化を増加させて、glMultMatrix()を使って、それらの変化の上に、蓄積された現在の変化(最後のフレームからの)を増加させます。

ModelView行列を1つのフレームあたり1回取り出すことがアプリケーションの性能への有害なインパクトを持つことができることに気づいている必要があります。 しかし、性能が1つのインプリメンテーションから次に変わるので、ベンチマークにこの操作が必要です。

9.080 glFrusum() と gluPerspective() を使う時の利点と欠点は何か?なぜ他のものよりそれを使った方が良いのですか?

glFrustum()および()両方ともgluPerspectiveであることは、目同等スペースから変化にクリップ同等スペースに使うことができるパースペクティブ投射行列を作り出します。 2の主要な違いは、glFrustum()がより一般的で、軸オフ投影を許し、() gluPerspectiveな間対称的な(軸オン)投影を生産することだけです。 実に、 実施する () gluPerspectiveであるように、glFrustum()を使用できます。 しかし、GLUインタフェースの自然な部分であるファンクションコールを層にすることは別として、性能有利が、() gluPerspectiveなので上のglFrustum()により生成された行列を使うことに全然ありません。

() gluPerspectiveであるというよりglFrustum()が一般的なので、ケースに() gluPerspectiveな時を使うことができます 使われえない 。 いくつかの例が、投射影、タイルを貼られた表現、およびステレオの眺めを含みます。

タイルを貼られる与えは、場面の種々のセクションをするために、複数軸オフ投影を用います。 結果は、最終的なイメージを生産するために、1回の大きいイメージ配列に組み立てられます。 最終的な表現の要求された次元がOpenGLインプリメンテーションの最大のビューポートサイズを越えている時には、しばしばこれが必要です。

ステレオの眺めにおいて、同じ場面の2つの表現が、わずかにシフトされた眺め位置によってされます。 眺め軸が「目」にすぐあるので、個々の眺めは、正しいビジュアルな結果を達成するために、どちらの側にでもわずかな軸オフ投影を用いなければなりません。

9.085 glFrustum() を呼ぶときに、gluPerspective() に合わせるようにするにはどうすれば良いですか?

glFrustum()呼び出しの眺め(fov)のフィールドは下記です:

fov*0.5 = arctan((トップ底)*0.5 /それ)の近くで

==-以来、() gluPerspectiveなので、対称的な投射 that のためのトップが産出します そして :

トップ=日焼け(fov*0.5)* 近く 
底=-トップ

左右のパラメータは、トップ、底、およびであり、単に機能します:

左=面*底
右=面*トップ

OpenGL参照マニュアル(私はどこでこれを得ますか?)が、両方の機能により作り出された行列を示します。

9.090 スクリーンいっぱいの四角形を描くにはどうすれば良いですか?

通常この問題が意味していること、「私は、どのように、全体のOpenGLビューポートを満たすクワタを引きますか?」。 これをするために、多くの方法があります。

最も直接的な方法は、要求された絵の具をセットし、投射とModelView行列を、アイデンティティおよび呼び出しglRectf()または等しいGL_QUADSプリミティブを引きなさいに設定することです。 長方形またはクワタのZ価値は、–1.0から1.0までの範囲にあるはずで、–1.0は、zNearを切り取っている飛行機、およびzFarを切り取っている飛行機への1.0にマッピングします。

ここの例として、zNearを切り取っている飛行機であり、どのようにフルスクリーンクワタを引きますか:

glMatrixMode(GL_MODELVIEW);
glPushMatrix ();
glLoadIdentity ();
glMatrixMode(GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glBegin(GL_QUADS);
glVertex3i (-1、-1、および-1);
glVertex3i (1、-1、および-1);
glVertex3i (1、1、および-1);
glVertex3i (-1、1、および-1);
glEnd ();
glPopMatrix ();
glMatrixMode(GL_MODELVIEW);
glPopMatrix ();

アプリケーションは、クワタが最大のZに見積もらせてほしいかもしれず、その場合、-1の代わりにZ値で使われるべきです。

フルスクリーンクワタにペイントする時には、指定されたバッファにだけ触れるように、いくつかのバッファから離れてマスキングすることが有益であるかもしれません。 例えば、色バッファから離れてマスキングし、深さ機能をGL_ALWAYSに設定できます。従って、深さバッファだけがペイントされます。 また、バッファのセットされる型板緩衝器またはどのような結合でも許すために、マスクをセットできます。

9.100 与えられたオブジェクト空間座標に対応するスクリーン座標を得るにはどのようにしたら良いですか?

もし少しの頂点のためにそれを見つける必要があるだけならば、GLUライブラリgluProject()ユーティリティルーチンを使うことができるでしょう。 多くの座標のために、フィードバックメカニズムを使うことがより効率的であるかもしれません。

gluProject()を使うために、ModelView行列、投射行列、ビューポート、およびインプットオブジェクトスペース座標を提供する必要があります。 スクリーンスペース座標は、X、Y、およびZのために戻されて、Zは標準化します(0 <= Z <= 1)。

9.110 スクリーン上のピクセルに対応するオブジェクト空間座標を求めるにはどうしたら良いですか?

GLUライブラリはgluUnProject()機能をこの目的に提供します。

Xのインプットスクリーン同等Z値、興味のY位置を得るために、深さバッファを読む必要があります。 これは次の通りコード化できます:

GLdouble z;

glReadPixels(x、y、1および1、GL_DEPTH_COMPONENT、GL_DOUBLE、&z);

左下コーナーでxyがOpenGL中心であることで(0と0)に注意してください。

スクリーンスペースX、Yを提供する必要があり、Zは、興味の具体的なピクセルがされた時間に流通したModelView行列、投射行列、およびビューポートによって、gluUnProject()へのインプットとして見積もります。

9.120 モデルビューマトリックスだけで変形する頂点座標を見つけるにはどのようにしたら良いですか?

しばしば、頂点の目同等スペース価値を得ることが有益です(すなわち、ModelView行列により変換されたオブジェクトスペース頂点)。 現在のModelView行列を取り出し、簡単なベクトルを実行することによってこれを得ることができます /行列増加。

9.130 表示画面から得られた点のオブジェクト空間座標での距離を求めるにはどうしたら良いですか?

ModelView行列をそれに乗算してポイントを目同等のスペースに変換してください。 そして、起源からのその距離を単に計算してください。 (もしこれが働かないならば、眺め変化を投射行列スタックに間違って置いたでしょう。)

9.140 ウィンドウのサイズ変更後も正しいアスペクト比を保つにはどうしたら良いですか?

それは、どのように投射行列を設定しているかに依拠しています。 ともかく、ウィンドウの新しい次元(幅と高さ)を知っている必要があります。 どのようにこれらを得るかが、どのプラットフォームを使っているかに依拠しています。 GLUT、例えば次元に、パラメータとして、作り直す機能コールバックに通過します。

以下は、ウィンドウと同じサイズであるビューポートを維持していると想定します。 もしではないならば windowWidthとwindowHeightのための代用のviewportWidthとviewportHeight 。

もし投射行列を設定するために、() gluPerspectiveなので、使っているならば、2番目のパラメータは縦横比をコントロールします。 プログラムがウィンドウリサイズをつかむ時には、投射行列を次の通り変更する必要があります:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspectiveです(fov、(フロート)windowWidth/(フロート)windowHeight、zNear
、zFar);

もしglFrustum()を使っているならば、縦横比は眺めボリュームの幅によって眺めボリュームの高さに変わります。 以下のウィンドウによって1:1縦横比を維持してさしつかえありません コードをリサイズする :

フロートcx、halfWidth = windowWidth*0.5f;
フロート面=(フロート)windowWidth/(フロート)windowHeight;

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/*cxは、X */ glFrustumのzNear飛行機の目スペースセンターです(cx-halfWidth*aspect
、cx+halfWidth*aspect、底、トップ、zNear、zFar);

glOrtho()とgluOrtho2D()はglFrustum()と同様です。

9.150 OpenGL は左手座標系の空間を使うことができますか?

OpenGLは、右-から左ききの座標に変わるように、モードスイッチを持っていません。 しかし、ModelView行列の上にネガティブなZスケールを増加させて左ききの座標系を容易に得ることができます。 例えば:

glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glScalef(1.、1.、および-1。);
増加眺めはいつものように変わります… */ /*増加モデルはいつものように変わります…
 */

9.160 あるオブジェクトまたは点を指すか、後を追うような形でオブジェクトを変形させることができますか?

オブジェクトのローカルな座標系から、要求された方向に直面している座標系に変わる行列を構成する必要があります。 どのようにこのタイプの行列が作成されるかをわかるために、この例コードを見てください

もし単に、いつもそれがビューアに直面するように、オブジェクトをしたいならば、アイデンティティに設定されるModelView行列によってそれを目同等のスペースに単に表現することを考慮するでしょう。

9.162 オブジェクトを揺らしたり、ピッチ&ロール変換するには?

変化行列の左上3x3部分は、ポスト変化同等スペースの新しいX、Y、およびZ斧により構成されています。

もし新しい変化がロールであるならば、それらを回転させて新しいローカルなYとX斧を計算してください ローカルなZ軸のまわりの「巻」度 。 もし変化がピッチまたは偏走であるならば、同様な計算をしてください。 そして、新しいローカルなX、Y、およびZ斧を、アイデンティティ行列の左上3x3部分に挿入して変化行列を単に構成してください。 この行列をパラメータとしてglMultMatrix()に通過できます。

より一層の回転は新しいローカルな斧のまわりで計算されるべきです。 これは、必然的に、経験のない3Dプログラマーのために紛らわしいかもしれない任意の軸についての回転を必要とします。 これはリニアの代数学の基本的概念です。

多くのプログラマーは、すぐに、X、Y、およびZ斧についての連続したglRotate()呼び出しとして合計3つの変化−−偏走、ピッチ、ロール−−を適用します。 これは作成gimbalの不利をロックさせて、それにおいて結果はglRotate()呼び出しの似で依存します。

9.170 鏡を描くにはどのようにしたら良いですか?

そして、1回で、それが鏡に映されているので、正常(不反射)眺めから場面を1回2回してください。 例コードはこのテクニックを示します。

軸位置合わせされた鏡〈YZ飛行機の鏡などの〉のために、反映された場面は、簡単なスケールによってされて、翻訳できます。 鏡の正常と一致している軸の-1.0で測量し、2倍の鏡の距離で起源から翻訳してください。 適所でのこれらの変化によって場面をすることにより、鏡に映されている場面は産出されます。 眺め変化をその前の価値に回復するために、行列スタックを使用してください。

次に、呼び出しにおいてglClearに深さバッファを承認してください(GL_DEPTH_BUFFER_BIT)。 そして、鏡をしてください。 完全な反射鏡のために、深さバッファにだけ与えてください。 それらがいくらかのライトを吸収するので、現実の鏡は完全な反射板ではありません。 この効果を作成するためには、0.05のアルファによって黒い鏡をするために、混合を用いてください。 glBlendFunc(GL_SRC_ALPHA、GL_ONE_MINUS_SRC_ALPHA)は、この目的のためのよい混合機能です。

最後に、不反映であった場面をしてください。 まさに鏡の反映された場面の部分ではなく全体の反映された場面が色バッファに存在して以来、見えるはずがない反映された場面のエリアに上書きするために、すべてのピクセルに触れる必要があります。

9.180 自分の空間内での大きさを計るにはどうしたら良いですか?

OpenGLは、そしてクリップ座標を得る投射行列によってModelView行列を座標に乗算します。 標準化された機器座標を得ることはその時パースペクティブ分割を実行します。 それは、距離と思われていることにおける幾何学 フォアグラウンドの幾何学より小さい によって、パースペクティブに与えることを作成するパースペクティブ部門ステップです。 パースペクティブ部門段階は、以下などの切り取っている同等なW価値によって、同等な価値を切り取っているXYZを分割することによって遂行されます:

Xndc=Xcc/Wcc
Yndc=Ycc/Wcc
Zndc=Zcc/Wcc

あなた自身のパースペクティブ訂正をするために、切り取っている同等なW価値を得る必要があります。 フィードバックバッファは、機器座標のXYZおよびクリップ座標のWをhomogenousな座標に提供します。 してもよく glGetFloatv(GL_CURRENT_RASTER_POSITION、…) 、W価値は、また、切り取っている座標にある一方、XYZは機器座標にあります。