ギャグ
1年前、
サイモン氏による一連の非常に興味深い記事に出会いました。 サイモンは、ゲームの作成方法、つまりゲーム内の要素のグラフィックソリューションを分解するのが大好きです。
プレートの端の切りくずから始まり、
オブジェクトからの断片の切り取りの実装方法で終わり
ます 。 しかし、特に興味深いのは、
Render Hellという一般的なタイトルの下にある彼の一連の記事であり、3Dオブジェクトが鉄レベルで(およびプログラム的にも)レンダリングされる方法を詳しく説明しています。
無料翻訳。 私は自分自身でそれをしたので、ある時点で戻って最初につかめなかったり、忘れたりすることができないものを読むことができました。
さあ、始めましょうか?
予約する。 復習
(元の本は
こちら )
ちょっと待ってください。PCの観点から見ると、3Dでの作業は頂点とテクスチャのリストに過ぎません。 このデータはすべてNext-gene画像に変換され、これは主にシステムプロセッサ(
CPU )とグラフィックプロセッサ(
GPU )を使用して行われます。
最初に、データはハードディスク(
HDD )からランダムアクセスメモリ(
RAM )にダウンロードされ、すばやくアクセスできます。 その後、オブジェクト(
Meshes )と表示(レンダリング)に必要なテクスチャがビデオカードのRAM(
VRAM )にロードされます。 これは、ビデオカードのVRAMへのアクセスがはるかに高速であるためです。
テクスチャが不要になった場合(VRAMでのアンロード後)、RAMから削除できます(ただし、HDDからのアンロードには非常に長い時間がかかるため、近い将来テクスチャが不要になることを確認する必要があります)。
ほとんどの場合、プロセッサは、たとえば衝突を判断するためにメッシュにアクセスする必要があるため、メッシュはRAMに残しておく必要があります。
第2版で補足これで、ビデオカード上のすべての情報(ビデオカードのRAM-VRAM)に保存されます。 ただし、VRAMからGPUへの転送速度は依然として低速です。 GPUは、受信するよりもはるかに多くの情報を処理できます。
そのため、エンジニアは少量のメモリをビデオプロセッサ(GPU)自体に直接配置し、このメモリキャッシュ(キャッシュ)と名付けました。 これは、大量のメモリをプロセッサに直接配置すると非常に高価になるため、少量のメモリです。 GPUは、現在必要なものを少しずつキャッシュにコピーします。
コピーされた情報は現在、レベル2キャッシュ(L2キャッシュ)にあります。 基本的に、これは少量のメモリで(たとえば、NVDIA GM204では2048 KBです)、GPUにインストールされ、VRAMよりもはるかに高速に読み取り可能です。
しかし、これでも効率的に作業するには十分ではありません! したがって、まだ小さなレベル1キャッシュ(L1キャッシュ)があります。 NVIDIA GM204では384KBであり、GPUだけでなく、最も近いコプロセッサーでも使用できます。
さらに、GPUコアの入出力データ用に設計された別のメモリがあります。ファイルの登録と記録用です。 ここから、GPUは、たとえば2種類の値を受け取り、それらを考慮して、結果をレジスタに書き込みます。
次に、これらの結果はL1 / L2 / VRAMに戻され、新しい計算のためのスペースが確保されます。 プログラマーとして、あなたは通常彼らの計算を心配するべきではありません。
なぜこれがすべて問題なく機能するのですか? 上記のように、アクセス時間がすべてです。 そして、たとえばHDDとL1キャッシュなどのアクセス時間を比較すると、両者の間にブラックホールがあります。それが違いです。 このリンクで正確な遅延の数値について読むこともできます:
gist.github.com/hellerbarde/2843375 レンダリングが点灯し始める前に、CPUはメッシュのレンダリング方法を記述するいくつかのグローバル値を設定します。 これらの値は、レンダリング状態と呼ばれます。
レンダリング状態これらは、メッシュのレンダリング方法に関する一種のパラメーターです。 パラメーターには、テクスチャーの種類、後続のメッシュ、ライト、透明度などを描画するために使用する頂点シェーダーとピクセルシェーダーに関する情報が含まれます。
理解することが重要:CPUがレンダリングのためにGPUに送信する各メッシュは、それ以前に指定されたパラメーター(レンダリング状態)でレンダリングされます。 つまり、剣、石、椅子、車をレンダリングできます。これらの各オブジェクトの前にRenderStateレンダリングオプションを指定しない場合、それらはすべて同じテクスチャの下でレンダリングされます。
すべての準備が完了すると、CPUは最終的にGPUを呼び出して、描画する必要があるものを言うことができます。 このチームはドローコールと呼ばれます。
ドローコールこれは、1つのメッシュをレンダリングするGPUのCPUコマンドです。 このコマンドは、レンダリング用の特定のメッシュを示し、マテリアルなどに関する情報は一切含まれていません-これらはすべてレンダリング状態で示されます。
メッシュはすでにVRAMにロードされています。
コマンドが送信された後、GPUはRenderStateデータ(マテリアル、テクスチャ、シェーダー)、およびオブジェクトの頂点に関するすべての情報を取得し、このデータを画面上の美しいピクセルに変換します(信じたいです)。 この変換プロセスはパイプラインと呼ばれます(Googleはこの単語を「パイプライン」と翻訳することを好みます)。
パイプライン前述のように、オブジェクトは頂点とテクスチャ情報のセットにすぎません。 これを脳を支える画像に変換するために、ビデオカードは頂点から三角形を作成し、頂点の点灯方法を計算し、頂点にテクスチャを描画します。
これらのアクションはパイプライン状態と呼ばれます。 ほとんどの場合、この作業のほとんどはビデオカードのGPUを使用して行われます。 ただし、たとえば、三角形の作成は、ビデオカードの他のコプロセッサを使用して実行される場合があります。
第2版で補足この例は非常に単純化されており、概観または「論理」パイプラインと見なす必要があります。各三角形/ピクセルは論理ステップを通過しますが、実際に起こることは説明したものとわずかに異なります。
次に、鉄が1つの三角形に対して行うステップの例を示します。
画像は、数万、数十万の同様のタスクを解決することでレンダリングされ、画面上に数百万のピクセルがレンダリングされます。 そして、これはすべて(少なくとも)1秒あたり30フレームに収まるはずです(願っています)。
ビデオプロセッサが数千のコアを持っている場合(CPUほど強力ではないが、多数の頂点やその他のデータを処理するのに十分な強力な場合)、最新のプロセッサはそれぞれ6〜8コアを備えています。
ブック番号2は、グラフィックプロセッサの高レベルと低レベルの構成の詳細に当てられています。
情報(たとえば、頂点の束)がパイプラインに到達すると、いくつかのコアが頂点から本格的なイメージに変換する作業を実行するため、これらの要素の束が同時に(並行して)イメージに形成されます。
これで、GPUが情報を並列処理できることがわかりました。 しかし、CPUとGPU間の通信はどうでしょうか? CPUは、GPUが新しいタスクを送信する前に作業を完了するまで待機しますか?
いや!
幸いなことにそうではありません! この理由は、CPUが次のタスクを十分に迅速に送信できないときにボトルの首のように形成される弱いリンクです。 ソリューションは、CPUが前の命令を処理している間にGPUに命令を追加する命令のリストです。 このシートはコマンドバッファーと呼ばれます。
コマンドバッファ命令バッファにより、CPUとGPUを互いに独立させることができます。 CPUが何かをレンダリングする場合、オブジェクトをコマンドキューに詰め込み、GPUが解放されると、シート(バッファー)からそれらを取得してコマンドの実行を開始します。 チームを編成する原則は、実行の順序です。 最初のコマンドが来て、最初のコマンドが実行されます。
ところで、異なるチームがあります。 たとえば、1つのコマンドはDrawCall、2番目のコマンドはRenderStateを新しいパラメーターに変更できます。
まあ、一般的に、これは最初の本です。 これで、情報がどのようにレンダリングされ、描画呼び出し、レンダリング状態が呼び出され、CPUとGPUが相互作用するかがわかります。
終わり。