ここでは、OpenGL APIに基づく回転三角形を備えたTriangle.exeと呼ばれる小さなC++プログラムのスクリーンショットを見ることができます。
確かに非常に基本的な例ですが、他のグラフィックカードの操作にも適用できると思います。
WindowsでTriangle.exeをダブルクリックすることからプロセス全体を知りたいと思っていたXPモニターで三角形が回転しているのが見えるまで。 .exeを処理する)とGPU(最終的に画面に三角形を出力する)は相互作用しますか?
この回転する三角形の表示に関係しているのは、主に次のハードウェア/ソフトウェアであると思います。
ハードウェア
ソフトウェア
誰かがそのプロセスを説明できますか?たぶん説明のためのある種のフローチャートで?
これは、すべてのステップを網羅する複雑な説明ではなく(範囲を超えると思われます)、中間のIT担当者が従うことができる説明です。
ITプロフェッショナルと名乗る多くの人がこのプロセスを正しく説明できなかったと私は確信しています。
私はプログラミングの側面と、コンポーネントが互いに対話する方法について少し書くことにしました。多分それは特定の領域にいくつかの光を当てるでしょう。
質問で投稿した1つの画像を画面に描画するにはどうすればよいですか。
画面上に三角形を描く方法はたくさんあります。簡単にするために、頂点バッファーが使用されていないと仮定しましょう。 (Avertex bufferは、座標を格納するメモリの領域です。)プログラムが単にすべての頂点についてグラフィックス処理パイプラインに通知したと仮定しましょう(頂点は空間内の単なる座標です) )続けて。
しかし、何かを描く前に、まず足場を実行する必要があります。 なぜなのかは後でわかります:
// Clear The Screen And The Depth Buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset The Current Modelview Matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Drawing Using Triangles
glBegin(GL_TRIANGLES);
// Red
glColor3f(1.0f,0.0f,0.0f);
// Top Of Triangle (Front)
glVertex3f( 0.0f, 1.0f, 0.0f);
// Green
glColor3f(0.0f,1.0f,0.0f);
// Left Of Triangle (Front)
glVertex3f(-1.0f,-1.0f, 1.0f);
// Blue
glColor3f(0.0f,0.0f,1.0f);
// Right Of Triangle (Front)
glVertex3f( 1.0f,-1.0f, 1.0f);
// Done Drawing
glEnd();
グラフィックカードを使用したいプログラムを書くとき、あなたは通常、ドライバーへのある種のインターフェースを選ぶでしょう。ドライバーに対するいくつかのよく知られているインターフェイスは次のとおりです。
この例では、OpenGLを使用します。これで、ドライバーへのインターフェースが、プログラムtalkをグラフィックスカードに作成するために必要なすべてのツールを提供します(または、ドライバーがカードに通信します)。
このインターフェイスは、特定のtoolsを提供するようにバインドされています。これらのツールは、プログラムから呼び出すことができる [〜#〜] api [〜#〜] の形をとります。
このAPIは、上記の例で使用されているものです。詳しく見てみましょう。
実際に描画を行う前に、setupを実行する必要があります。ビューポート(実際にレンダリングされる領域)、遠近法(カメラから世界へ)、使用するアンチエイリアス(スムーズにするため)を定義する必要がありますあなたの三角形の縁)...
しかし、それについては取り上げません。 すべてのフレームで実行する必要のあるものをのぞいてみます。お気に入り:
グラフィックパイプラインがフレームごとに画面をクリアするわけではありません。あなたはそれを言わなければならないでしょう。どうして?これが理由です:
画面をクリアしないと、フレームごとに単純に上に描画します。そのため、GL_COLOR_BUFFER_BIT
を設定してglClear
を呼び出します。他のビット(GL_DEPTH_BUFFER_BIT
)は、OpenGLにdepthバッファーをクリアするように指示します。このバッファーは、どのピクセルが他のピクセルの前(または後ろ)にあるかを判別するために使用されます。
変換は、すべての入力座標(三角形の頂点)を取り、ModelView行列を適用する部分です。これは、が(= /// =)モデル(頂点)の回転、スケーリング、および変換(移動)の方法を説明するマトリックスです。
次に、射影行列を適用します。これにより、すべての座標が移動して、カメラの向きが正しくなります。
ここで、ビューポートマトリックスを使用してもう一度変換します。これは、モデルをモニターのサイズにスケーリングするために行います。これで、レンダリングの準備ができた頂点のセットができました!
少し後で変換に戻ります。
三角形を描くには、glBegin
をGL_TRIANGLES
で呼び出して、三角形の新しいリストを開始するようにOpenGLに指示するだけです。絶え間ない。
あなたが描くことができる他の形もあります。 三角形の帯 または 三角形の扇形 のように。同じ量の三角形を描画するためにCPUとGPU間の通信が少なくて済むため、これらは主に最適化です。
その後、各三角形を構成する3つの頂点のセットのリストを提供できます。すべての三角形は3つの座標を使用します(3D空間にいるため)。さらに、glColor3f
beforeを呼び出すことにより、各頂点にcolorも提供しますglVertex3f
。
3つの頂点(三角形の3つの角)間の陰は、OpenGLによって自動的に計算されます。ポリゴンの面全体に色を補間します。
ここで、ウィンドウをクリックすると、アプリケーションは、クリックを通知する ウィンドウメッセージ のみをキャプチャする必要があります。次に、プログラムで任意のアクションを実行できます。
これは、3Dシーンの操作を開始したい場合、lotより困難になります。
まず、ユーザーがウィンドウをクリックしたピクセルを明確に把握する必要があります。次に、パースペクティブを考慮に入れて、シーン内へのマウスクリックのポイントから光線の方向を計算できます。次に、シーン内のオブジェクト がそのレイと交差する かどうかを計算できます。これで、ユーザーがオブジェクトをクリックしたかどうかがわかります。
それで、どうやってそれを回転させるのですか?
一般的に適用される2つのタイプの変換を認識しています。
違いは、bonesが単一のverticesに影響することです。行列は、常にすべての描画された頂点に同じ方法で影響します。例を見てみましょう。
以前は、三角形を描く前に identity matrix をロードしました。単位行列は、単に変換を提供するだけです変換なし。だから、私が描くものは何でも、私の見方によってのみ影響を受けます。したがって、三角形はまったく回転しません。
今それを回転したい場合は、自分で(CPUで)計算を行い、(回転する)other座標でglVertex3f
を呼び出すだけです。または、描画する前に glRotatef
を呼び出して、GPUにすべての作業を行わせることもできます。
// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);
amount
は、もちろん、単なる固定値です。 animateにしたい場合は、amount
を追跡し、フレームごとに増やす必要があります。
この簡単な例では、行列を気にする必要はありません。単にglRotatef
を呼び出すだけで、すべてが処理されます。
glRotate
は、ベクトルx y zを中心としたangle
度の回転を生成します。現在の行列( glMatrixMode を参照)は、次の行列を引数として glMultMatrix が呼び出されたかのように、現在の行列を置き換える積で回転行列が乗算されます。x 21-c + cxy1-c-zsxz1-c + ys 0 yx1-c + z sy sy 21-c + cyz 1-c-xs 0 xz1-c-ysyz1-c + xsz 21-c + c 0 0 0 0 1
まあ、それをありがとう!
明らかになるのは、OpenGLへの話し合いがしていることです。しかし、それはusに何も伝えていません。コミュニケーションはどこにありますか?
この例でOpenGLが伝えているのは、完了したときだけです。すべての操作には一定の時間がかかります。一部の操作には信じられないほど長い時間がかかり、他の操作は信じられないほど迅速です。
GPUへの頂点の送信は非常に高速になるので、それを表現する方法すらわかりません。何千もの頂点をCPUからGPUに送信する場合、フレームごとに、ほとんど問題はありません。
画面のクリアには、ミリ秒またはそれ以上かかる場合があります(通常、各フレームを描画する時間は約16ミリ秒しかありません)。ビューポートの大きさによって異なります。それをクリアするには、OpenGLはクリアしたい色ですべてのピクセルを描画する必要があります。
それ以外は、グラフィックアダプターの機能(最大解像度、最大アンチエイリアシング、最大色深度など)についてOpenGLに質問するだけです。
しかし、それぞれ特定の色を持つピクセルでテクスチャを塗りつぶすこともできます。したがって、各ピクセルは値を保持し、テクスチャはデータで満たされた巨大な「ファイル」です。 (テクスチャバッファーを作成することによって)グラフィックカードにロードし、次に shader をロードして、シェーダーにテクスチャを入力として使用し、「ファイル」で非常に重い計算を実行するように指示できます。
次に、計算結果を(新しい色の形で)新しいテクスチャに「レンダリング」できます。
これが、他の方法でGPUを機能させる方法です。 CUDAはその側面と同じように機能すると思いますが、CUDAで作業する機会がありませんでした。
私たちは本当に主題全体に少しだけ触れました。 3Dグラフィックプログラミングは獣の地獄です。
自分が理解していないことを正確に理解することは困難です。
GPUには、BIOSがマップする一連のレジスタがあります。これらにより、CPUはGPUのメモリにアクセスし、GPUに操作を実行するように指示できます。 CPUはこれらのレジスタに値をプラグインして、GPUのメモリの一部をマップし、CPUがそれにアクセスできるようにします。次に、そのメモリに命令をロードします。次に、CPUがメモリにロードした命令を実行するようにGPUに指示する値をレジスタに書き込みます。
この情報は、GPUが実行する必要のあるソフトウェアで構成されています。このソフトウェアはドライバーにバンドルされており、ドライバーは(両方のデバイスでコードの一部を実行することにより)CPUとGPUの間で分割された責任を処理します。
次に、ドライバーは、GPUメモリへの一連の「ウィンドウ」を管理して、CPUが読み書きできるようにします。一般に、アクセスパターンでは、CPUが命令または情報をマップされたGPUメモリに書き込んでから、レジスタを介してGPUに命令を実行するか、その情報を処理するように指示します。情報には、シェーダーロジック、テクスチャなどが含まれます。
WindowsでTriangle.exeをダブルクリックすることからプロセス全体を知りたいと思っていたXPモニターで三角形が回転しているのが見えるまで。 .exeを処理する)とGPU(最終的に画面に三角形を出力する)は相互作用しますか?
オペレーティングシステムで実行可能ファイルがどのように実行され、その実行可能ファイルがGPUからモニターに送信される方法は実際にはわかっているが、その間で何が起こっているかはわからないと仮定しましょう。それでは、ハードウェアの側面から見て、さらに プログラマーの側面 答えを拡張してみましょう...
ドライバーを使用して、CPUはPCIなどのマザーボード機能を介して通信できますグラフィックカードとそれにいくつかのGPU命令を実行するためのコマンドを送信 アクセス/ GPUメモリを更新 、GPUで実行されるコードをロードするなど.
ただし、コードからハードウェアやドライバーに直接話しかけることはできません。したがって、これはOpenGL、Direct3D、CUDA、HLSL、CgなどのAPIを介して行われる必要があります。前者はGPU命令を実行し、GPUメモリを更新しますが、後者は物理/シェーダー言語であるため、実際にはGPUでコードを実行します。
CPUは日常のワークステーションとサーバープログラムの実行に優れていますが、最近のゲームで目にする光沢のあるグラフィックについてはあまり考えられていませんでした。昔は、いくつかの2Dおよび3Dのことからトリックを実行するソフトウェアレンダラーがありましたが、非常に制限されていました。そこで、ここでGPUが登場しました。
GPUは、グラフィックスで最も重要な計算の1つMatrix Manipulationに最適化されています。 CPUは、行列操作の各乗算を1つずつ計算する必要があります(後で、 DNow! や [〜#〜] sse [〜#〜] など)追いついた)、GPUはこれらすべての乗算を一度に実行できます!並列処理。
しかし、並列計算だけが理由ではありません。もう1つの理由は、GPUがビデオメモリに非常に近いため、CPUを介して往復するよりもはるかに高速になることです。
これをすべて機能させるために欠けている部分が1つあります。書き込むことができるものが必要で、それを読み取って画面に送信できます。これを行うには、framebufferを作成します。どのような操作を行っても、最終的にはフレームバッファーのピクセルを更新します。場所の他に、色と深度に関する情報も保持されます。
どこかにBlood Sprite(画像)を描画したい例を挙げましょう。まず、ツリーテクスチャ自体がGPUメモリに読み込まれるため、必要に応じて簡単に再描画できます。次に、スプライトを実際にどこかに描画するには、頂点を使用して(正しい位置に配置して)スプライトを変換し、ラスター化(3Dオブジェクトからピクセルに変換)して、フレームバッファーを更新します。より良いアイデアを得るために、WikipediaのOpenGLパイプラインのフローチャートを以下に示します。
これはグラフィックスアイデア全体の主な要点であり、より多くの研究が読者の宿題です。
簡単にするために、次のように説明できます。一部のメモリアドレスは、RAMではなくビデオカード用)に予約されています(BIOSおよび/またはオペレーティングシステムによって)。これらの値(ポインタ)で書き込まれたデータはすべてカードに送られます。プログラムは、アドレス範囲を知るだけでビデオカードに直接書き込むことができます。これは、昔のやり方とまったく同じです。最近のOSでは、これはビデオドライバーや上部のグラフィックライブラリ(DirectX、 OpenGLなど)。
GPUは通常、DMAバッファーによって駆動されます。つまり、ドライバーはユーザー空間プログラムから受け取ったコマンドを命令のストリームにコンパイルします(状態を切り替え、これをそのように描画し、コンテキストを切り替え、など)、それらはデバイスメモリにコピーされ、PCIレジスタまたは同様の方法でこのコマンドバッファーを実行するようにGPUに指示します。
したがって、描画呼び出しなどのたびに、ユーザー空間ドライバーがコマンドをコンパイルし、割り込みを介してカーネル空間ドライバーを呼び出し、最後にコマンドバッファーをデバイスメモリに送信して、GPUにレンダリングを開始するように指示します。
特にPS3では、コンソールですべてを自分で行うこともできます。
私は、CPUがグラフィックカードに何を実行するように指示しているのか、なぜグラフィック関連のコマンド(openglやdirect3dコマンドなど)がGPUに直接送信されないのかがわかりません。
CPUはGPUに何をレンダリングするかを指示するだけです。すべての命令は、最初にCPUを通過し、GPUが実際にレンダリングを行うためにセットアップ/初期化されます。
CPUがビデオデータをバス経由でGPUに送信し、GPUがそれを表示すると思います。したがって、より高速なGPUはCPUからのより多くのデータを処理できます。このように、GPUへのcpuoffloadの処理の一部。したがって、ゲームの速度が速くなります。
これは、RAMのようなもので、CPUがデータを格納するため、すばやくロードして処理できます。どちらもゲームを高速化します。
または、サウンドカードまたはネットカードが同じ原理で機能します。つまり、データを取得し、CPUの作業の一部をオフロードします。