ここでは、OpenGL APIに基づいて三角形を回転させるTriangle.exeという小さなC++プログラムのスクリーンショットを見ることができます
非常に基本的な例ですが、他のグラフィックカードの操作にも応用できると思います
Windows XPでTriangle.exeをダブルクリックしてから、モニターに三角形が回転しているのが見えるようになるまでのプロセスを知りたいと思っていました。どうなるのか、CPU(最初に.exeを処理する)とGPU(最終的に画面上に三角形を出力する)はどのように相互作用するのでしょうか?
私は、この回転する三角形の表示に関与して、主に他の人の間で次のハードウェア/ソフトウェアであると推測します
Hardware
- HDD
- システムメモリ(RAM)
- CPU
- Video memory
- GPU
- LCD display
Software
- Operating System
- DirectX/OpenGL API
- Nvidia Driver
誰かプロセスを説明してくれる人はいますか?
一つ一つのステップを網羅した複雑な説明ではなく(範囲を超えてしまうのではないかと推測されますが)、中級者のIT担当者がフォローできるような説明である必要があります
ITのプロを自称するような人でも、このプロセスを正しく説明できない人が多いと思います
62 JohnnyFromBF 2012-08-13
プログラミングの側面と、コンポーネントがどのようにお互いに話をするかについて少し書くことにしました。もしかしたら、特定の分野に光を当てることができるかもしれません
The Presentation
質問に投稿したその一枚の画像が画面に描かれているだけでも何か意味があるのでしょうか?
画面上に三角形を描く方法はたくさんあります。簡単のために、頂点バッファを使用しなかったと仮定してみましょう(頂点バッファとは座標を格納するメモリ領域のことです)。(頂点バッファとは、座標を格納するメモリ領域のことです。) プログラムが、グラフィックス処理パイプラインに、行内のすべての頂点(頂点とは、空間上の座標)について単純に伝えたとしましょう
しかし、何かを描く前に、まず足場を走らせなければならない。その理由は後ほど
// 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
- Direct3D
- CUDA
この例では、OpenGL を使用します。さて、ドライバへのインターフェースは、プログラムをグラフィックスカード(またはドライバ)と通信させるために必要なすべてのツールを提供してくれます
このインターフェイスは、あなたに特定のツールを提供するためにバインドされています。これらのツールは、APIの形をしており、プログラムから呼び出すことができます
このAPIは、上の例で使用されているものです。もう少し詳しく見てみましょう
The Scaffolding
実際に描画を行う前に、セットアップを行う必要があります。ビューポート(実際にレンダリングされる領域)、パースペクティブ(カメラを世界に向ける)、使用するアンチエイリアス(三角形の縁を滑らかにする)を定義しなければなりません
でも、そんなものは見ない。ただ、1コマごとにやることを 覗いてみるだけです。例えば
画面をクリアする
グラフィックパイプラインはフレームごとに画面をクリアしてくれるわけではありません。それを伝える必要があります。なぜですか?これが理由です
画面をクリアしないと、単純にフレームごとに画面の上に描画することになります。これが、GL_COLOR_BUFFER_BIT
をセットした状態でglClear
を呼び出す理由です。もう一つのビット(GL_DEPTH_BUFFER_BIT
)は、OpenGLに深度バッファをクリアするように指示します。このバッファは、どのピクセルが他のピクセルの前(または後ろ)にあるかを判断するために使用されます
Transformation
変換は、すべての入力座標(三角形の頂点)を取り、ModelView行列を適用する部分です。これは、モデル(頂点)がどのように回転、拡大縮小、翻訳(移動)されるかを説明する行列です
次に、投影行列を適用します。これはすべての座標を移動させ、カメラの向きが正しくなるようにします
ここでもう一度、ビューポート行列を使って変換します。これは、モデルをモニタのサイズに合わせて拡大縮小するために行います。これで、レンダリングする準備ができた頂点のセットができました
変身については、もう少し後になります
Drawing
三角形を描くには、glBegin
をGL_TRIANGLES
定数で呼び出すことで、OpenGLに三角形の新しいリストを開始するように指示するだけです。 他にも描くことのできる形はあります。三角形の帯や三角形の扇子などです。これらは主に最適化されたもので、同じ量の三角形を描画するために CPU と GPU 間の通信が少なくて済むからです
その後、各三角形を構成する3つの頂点の集合のリストを提供することができます。すべての三角形は3つの座標を使います (3D空間にいるので)。さらに、glVertex3f
を呼び出す前にglColor3f
を呼び出すことで、各頂点の色を提供しています
3つの頂点(三角形の3つの角)の間の陰影は、OpenGLによって自動的に計算されます。ポリゴンの面全体の色を補間します
Interaction
さて、あなたがウィンドウをクリックしたとき。アプリケーションはクリックを知らせるウィンドウメッセージをキャプチャするだけです。そうすれば、あなたが望むプログラム内の任意のアクションを実行することができます
3Dシーンとのインタラクションを始めようとすると、これはもっと難しくなります
まず、ユーザーがどのピクセルでウィンドウをクリックしたかを明確に知る必要があります。その後、あなたの視点を考慮に入れて、マウスクリックのポイントからシーンへの光線の方向を計算することができます。そして、シーン内の任意のオブジェクトが その光線と交差するかどうかを計算することができますこれで、ユーザーがオブジェクトをクリックしたかどうかがわかります
では、どうやって回転させるのか?
Transformation
私が意識しているのは、一般的には2種類の変換が適用されているということです
- Matrix-based transformation
- Bone-based transformation
違いは、ボーンが単一の頂点に影響を与えることです。行列は常に同じように描画されたすべての頂点に影響を与えます。例を見てみましょう
Example
先ほど、三角形を描く前に 同一性行列 を読み込みました。アイデンティティ行列は、単純に変換を全く行わないものです。ですから、私が描くものは何であれ、私の遠近法の影響を受けるだけです。つまり、三角形は全く回転しません
今すぐ回転させたい場合は、(CPU上で)自分で計算して、(回転させた)他の座標で単純にglVertex3f
を呼び出すことができます。あるいは、描画前にglRotatef
を呼び出してGPUにすべての作業をさせることもできます
// Rotate The Triangle On The Y axis
glRotatef(amount,0.0f,1.0f,0.0f);
amount
はもちろん固定値でしかありません。アニメートしたい場合は、amount
の値を常に把握しておき、フレームごとに増やしていく必要があります
で 待って さっきの行列の話は どうなったの?
この単純な例では、行列を気にする必要はありません。単にglRotatef
を呼び出すだけで、すべての処理を代行してくれます
glRotate
は,ベクトル x y z を中心にangle
度の回転を生成します.glMatrixMode を参照してください)は,次の行列を引数として glMultMatrix が呼ばれた場合と同様に,その積を現在の行列に置き換えた回転行列で乗算されます.x 2 1 – c + c x y 1 – c – z s x z 1 – c + y s 0 y x 1 – c + z s y 2 1 – c + c y z 1 – c – x s 0 x z 1 – c – y s y z 1 – c + x s z 2 1 – c + c x s z 2 1 – c + c 0 0 0 1
ありがとうございます!
Conclusion
明らかになるのは、OpenGLには多くの話があるということだ。しかし、それは何も教えてくれません。通信はどこで行われているのでしょうか?
この例でOpenGLが私たちに伝えているのは、それがいつ行われるかということだけです。すべての操作には一定の時間がかかります。信じられないほど長い時間がかかる操作もあれば、信じられないほど速い操作もあります
頂点をGPUに送るのは、どう表現したらいいのかわからないくらい速いだろう。CPUからGPUに何千もの頂点を1フレームごとに送るのは、ほとんどの場合、全く問題ないでしょう
画面をクリアするには、ビューポートの大きさにもよりますが、ミリ秒かそれ以上の時間がかかります(通常、各フレームを描画する時間は約16ミリ秒しかないことを覚えておいてください)。それをクリアするために、OpenGLは、あなたがクリアしたい色のピクセルをすべて描画しなければならず、それは何百万のピクセルになる可能性があります
それ以外にも、グラフィックスアダプタの機能(最大解像度、最大アンチエイリアス、最大色深度、…)については、かなりOpenGLに聞くことしかできません
しかし、テクスチャを特定の色を持つピクセルで埋めることもできます。各ピクセルはこのようにして値を持ち、テクスチャはデータで埋め尽くされた巨大な「ファイル」となります。これをグラフィックスカードにロードして(テクスチャバッファを作成して)、shaderをロードし、そのシェーダに入力としてテクスチャを使用するように指示して、”ファイル “上で非常に重い計算を実行することができます
そして、計算の結果(新しい色の形で)を新しいテクスチャに「レンダリング」することができます
そうやってGPUを別の意味で働かせることができるんですね。CUDAはそういう面では似たようなことをすると想定しているのですが、それを使って仕事をする機会がありませんでした
本当にほんの少ししか触れていませんでした。3Dグラフィックスのプログラミングは、とんでもない野獣です
57 Der Hochstapler 2012-08-14
自分が理解していないことを正確に理解するのは難しい
GPUにはBIOSがマップする一連のレジスタがあります。これらのレジスタはCPUがGPUのメモリにアクセスし、GPUに操作を実行するように指示することを可能にします。CPUはこれらのレジスタに値を差し込んでGPUのメモリの一部をマップし、CPUがアクセスできるようにします。次に、そのメモリに命令をロードします。そして、CPUがメモリにロードした命令を実行するようにGPUに指示するレジスタに値を書き込みます
情報は、GPUが実行するために必要なソフトウェアで構成されています。このソフトウェアはドライバに同梱されており、ドライバはCPUとGPUの間で責任を分担している(コードの一部を両方のデバイスで実行することで)
次にドライバは,CPU が読み書き可能な GPU メモリへの一連の「ウィンドウ」を管理します.一般的に、アクセスパターンは、CPUがマッピングされたGPUメモリに命令や情報を書き込んでから、レジスタを介してGPUに命令を実行したり、その情報を処理したりするように指示することを含みます。情報には、シェーダロジックやテクスチャなどが含まれる
42 David Schwartz 2012-08-13
Windows XPでTriangle.exeをダブルクリックしてから、モニターに三角形が回転しているのが見えるようになるまでのプロセスを知りたいと思っていました。どうなるのか、CPU(最初に.exeを処理する)とGPU(最終的に画面上に三角形を出力する)はどのように相互作用するのでしょうか?
オペレーティングシステム上で実行ファイルがどのように実行され、その実行ファイルがどのようにGPUからモニターに送られるかは知っていても、その間に何が起こっているのかは知らないと仮定してみましょう。そこで、ハードウェアの側面から見て、プログラマの側面の答えをさらに拡張してみましょう
CPUとGPUのインターフェースは?
ドライバを使用して、CPUはグラフィックスカードにPCIのようなマザーボードの機能を介して話をすることができ、いくつかのGPU命令を実行するためにそれにコマンドを送信し、アクセス/GPUメモリを更新し、GPU上で実行されるコードをロードし、より多くの
しかし、コードからハードウェアやドライバに直接話しかけることはできません。前者はGPU命令を実行したり、GPUメモリを更新したりしますが、後者は物理/シェーダ言語であるため、実際にGPU上でコードを実行します
なぜCPUではなくGPUでコードを実行するのか?
CPUは私たちの日常のワークステーションやサーバーのプログラムを実行するのに適していますが、最近のゲームで見られるような光沢のあるグラフィックについてはあまり考えられていませんでした。昔は、2Dや3Dのものを処理するソフトウェアレンダラがありましたが、それは非常に制限されていました。そこで、ここでGPUの出番です
GPU は、グラフィックスで最も重要な計算の 1 つである行列操作のために最適化されています。CPU は行列操作の各乗算を 1 つずつ計算しなければなりません (後に、3DNow! や SSE のようなものが追いつきました) が、GPU はそれらの乗算を一度にすべて行うことができます。並列化です
しかし、並列計算だけが理由ではありません。もう一つの理由は、GPUがビデオメモリに非常に近く、CPUなどを経由して往復するよりもはるかに高速になります
これらのGPU命令/メモリ/コードはどのようにグラフィックを表示しますか?
これをすべて機能させるためには、1つ欠けている部分があります。これは、フレームバッファを作成することで実現できます。どのような操作をしても、最終的にはフレームバッファ内のピクセルを更新します
まず、木のテクスチャ自体はGPUメモリにロードされているので、好きなように描き直すことができる。次に、実際にどこかにスプライトを描くためには、頂点を使ってスプライトを変換(正しい位置に配置)し、ラスタライズ(3Dオブジェクトからピクセルに変換)し、フレームバッファを更新することができます。より良いアイデアを得るために、WikipediaのOpenGLパイプラインのフローチャートを参照してください
これは、全体のグラフィックのアイデアの主な要旨であり、より多くの研究は、読者のための宿題です
14 Tamara Wijsman 2012-08-15
簡単に説明すると以下のようになります。いくつかのメモリアドレスは(BIOSやオペレーティングシステムによって)RAM用ではなく、ビデオカード用に予約されています。これらの値(ポインタ)に書き込まれたデータはすべてビデオカードに送られます。理論的には、アドレス範囲を知っていれば、どんなプログラムでもビデオカードに直接書き込むことができ、昔はこのようにしていました。最近のOSでは、ビデオドライバやグラフィックライブラリ(DirectX、OpenGLなど)が管理しています
8 AZ. 2012-08-13
GPUは通常、DMAバッファによって駆動されます。つまり、ドライバは、ユーザ空間プログラムから受け取ったコマンドを、命令のストリーム(状態を切り替える、このように描画する、コンテキストを切り替えるなど)にコンパイルして、デバイスメモリにコピーします。そして、PCIレジスタまたは同様の方法でこのコマンドバッファを実行するようにGPUに指示します
そのため、描画呼び出しなどのたびに、ユーザースペースドライバがコマンドをコンパイルし、割り込みを介してカーネルスペースドライバを呼び出し、最終的にはデバイスメモリにコマンドバッファを送信してGPUにレンダリングを開始するように指示します
コンソールでは、特にPS3では、自分ですべてを行うことができる楽しみを持っていることさえできます
6 Axel Gneiting 2012-08-13
CPUはバスを介してGPUに動画データを送り、GPUはそれを表示していると思います。そのため、高速なGPUはCPUからのデータをより多く処理することができます。このようにして、cpuoffloadの処理の一部をGPUに転送します。そのため、ゲームのスピードが速くなります
これは、CPUがロードして素早く処理できるように、CPUが何かを保存するRAMのようなものです。どちらもゲームを高速化します
またはサウンドカードやネットカードは、同じ原理で動作し、それはデータを取得し、CPUのいくつかの仕事をオフロードしています
0 user583641 2016-04-16
opはCPUがグラフィックカードに何を指示しているのか、グラフィック関連のコマンド(openglやdirect3dコマンドなど)がGPUに直接送られてこないのはなぜなのか、よくわかっていないと思います
CPU は GPU に何をレンダリングするかを指示するだけです。すべての命令は、GPUが実際にレンダリングを行うためにセットアップ/初期化されるCPUを最初に通過します
0 dave 2016-08-01