0

私が見つけたチュートリアル、ガイド、書籍のほとんどは、OpenGL に関連しており、三角形を描画して OpenGL を初期化する方法を説明しています。それはいいです。しかし、彼らがそれを説明しようとすると、次のような一連の関数とパラメーターがリストされます。

glClear()
glClearColor()
glBegin()
glEnd()
...

私は暗記が苦手なので、「なぜこんなことをしているの?」という答えが常に必要です。チュートリアルでそう言われたからではなく、他のことをする前に特定のことを設定する必要があることを覚えているので、その関数の束を書きます。

glBegin()とで何かを描き始める前に、OpenGLに何を定義する必要があるのか​​ (純粋なOpenGLのみ、バックグラウンドライブラリとしてSFMLを使用していますが、それは実際には問題ではありません)を誰かに説明してもらえますglEnd()か?

回答例:

最初に、画面をクリアするために必要な色を OpenGL に伝える必要があります。現在のフレームの描画を開始する前に、各フレームを前のフレームでクリアする必要があるため...

4

2 に答える 2

9

まず、OpenGL はステート マシンであることを知っておく必要があります。つまり、(SFML によって行われる) OpenGL コンテキストの作成を除けば、初期化などはありません!

私は暗記が苦手なので、

これはいい…</p>

「なぜ私たちはこれをしているのですか?」に対する答えが常に必要です。

これは素晴らしいです!

glBegin() と glEnd() で何かを描画し始める前に、OpenGL (純粋な OpenGL のみ、バックグラウンド ライブラリとして SFML を使用していますが、それは実際には問題ではありません) に何を定義する必要があるかを誰かに説明してもらえますか?

すでに述べたように、OpenGL はステート マシンです。つまり、基本的には、状態の設定と操作の実行という 2 種類の呼び出しを行うことができます。

たとえば、フラグが設定されglClearColorた の呼び出し時に、アクティブなフレームバッファ カラーをクリアするために使用されるクリア カラーの状態変数を設定します。深度値 ( flag to ) にも同様の関数が存在します。glClearGL_COLOR_BUFFER_BITglClearDepthGL_DEPTH_BUFFER_BITglClear

glBegin廃止された OpenGL の即時モードにglEnd属します。したがって、それらを学ぶ理由はほとんどありません。代わりに頂点配列を使用する必要があります。頂点バッファー オブジェクトを使用することをお勧めします。

しかし、次のようになります: glBeginOpenGL を、 のパラメータとして選択された種類のプリミティブのジオメトリを描画する必要がある状態に設定しますglBeginGL_TRIANGLESたとえば、OpenGL は への 3 回の呼び出しごとglVertexに三角形を形成していると解釈するようになります。三角形のバッチが終了glEndたことを OpenGL に伝えます。glBegin…glEnd ブロック内では、特定の状態変更が許可されていません。ジオメトリの変換と、マトリックス、シェーダー、テクスチャ、およびその他の画像の生成に関係するすべてのものの中にあります。

よくある誤解の 1 つは、OpenGL が初期化されているというものです。initGLこれは、関数または類似の機能を備えた、不適切に作成されたチュートリアルによるものです。シーンのレンダリングを開始するときに、すべての状態を最初から設定することをお勧めします。しかし、1 つのフレームに複数のシーンが含まれる場合があるため (HUD や分割画面のゲームを考えてみてください)、これは 1 つのシーンで数回発生します。


アップデート:

では、どうやって三角形を描くのですか?まあ、それは十分に簡単です。まず、ジオメトリ データが必要です。たとえば、次のようになります。

GLfloat triangle[] = {
    -1, 0, 0,
    +1, 0, 0,
     0, 1, 0
};

render 関数では、glDrawArrays または glDrawElements への次の呼び出しがそこからデータをフェッチすることを OpenGL に伝えます (簡単にするために、ここでは OpenGL-2 関数を使用します)。

glVertexPointer(3, /* there are three scalars per vertex element */
                GL_FLOAT, /* element scalars are float */
                0, /* elements are tightly packed (could as well be sizeof(GLfloat)*3 */
                trignale /* and there you find the data */ );
/* Note that glVertexPointer does not make a copy of the data! 
   If using a VBO the data is copied when calling glBufferData. */

/* this switches OpenGL into a state that it will
   actually access data at the place we pointed it
   to with glVertexPointer */
glEnableClientState(GL_VERTEX_ARRAY);

/* glDrawArrays takes data from the supplied arrays and draws them
   as if they were submitted sequentially in a for loop to immediate
   mode functions. Has some valid applications. Better use index
   based drawing for models with a lot of shared vertices. */
glDrawArrays(Gl_TRIANGLE, /* draw triangles */
             0, /* start at index 0 */
             3, /* process 3 elements (of 3 scalars each) */ );

まだ含めていないのは、変換とビューポート マッピングの設定です。

ビューポートは、容易に投影され正規化されたジオメトリがウィンドウにどのように配置されるかを定義します。この状態は を使用して設定されglViewport(pos_left, pos_bottom, width, height)ます。

現在、変換は頂点シェーダーで行われます。基本的に、頂点シェーダーは特別な言語 (GLSL) で記述された小さなプログラムであり、頂点属性を取得し、結果の頂点のクリップ スペース位置を計算します。これに対する通常のアプローチは、固定関数パイプラインをエミュレートすることです。これは 2 段階のプロセスです。最初にジオメトリをビュー空間に変換し (照明などの一部の計算はこの空間の方が簡単です)、次にそれをクリップ空間に投影します。レンダラーのレンズ。固定機能のパイプラインには、このための 2 つの変換マトリックスがあります。Modelview と Projection です。目的の結果に必要なものに設定します。単なる三角形の場合、モデルビューのアイデンティティを残し、いずれかの次元で -1 から 1 までの正射影を使用します。

glMatrixMode(GL_PROJECTION);
/* the following function multiplies onto what's already on the stack,
   so reset it to identity */
glLoadIdentity(); 

/* our clip volume is defined by 6 orthogonal planes with normals X,Y,Z
   and ditance 1 from origin into each direction */
glOrtho(-1, 1, -1, 1, -1, 1); 

glMatrixMode(GL_MODELVIEW);
/* now a identity matrix is loaded onto the modelview */
glLoadIdentity();

変換を設定したら、上で概説したように三角形を描画できるようになりました。

draw_triangle();

最後に、コマンドの送信が完了し、レンダリングを終了する必要があることを OpenGL に伝える必要があります。

if(singlebuffered)
    glFinish();

ただし、ほとんどの場合、ウィンドウはダブルバッファリングされているため、それを交換して視覚的にする必要があります。スワップは終了しないと意味がないので、スワップは終了を意味します

else
    SwapBuffers();
于 2012-08-05T09:24:55.073 に答える
0

API を使用して、OpenGL ステート マシンを設定および変更しています。

実際には GPU に直接プログラミングするのではなく、アプリケーションと GPU の間の媒体を使用して、何をしようとしているのかを実行します。

このようになっており、CPU やメモリと同じように機能しない理由は、openGL が OS/システムに依存しないハードウェアで実行することを意図していたためです。プログラミングするものだけではありません。

したがって、このため、何をしようとしても、合理的な範囲内のすべてのシステム/OS/ハードウェアで実行できるようにする、プリセット コードの使用方法を学ぶ必要があります。

たとえば、特定のグラフィックス カード (amd など) を使用して Windows 8.1 でアプリケーションを作成する場合でも、アプリケーションを Andoird/iOS/Linux/他の Windows システム/Nvidia などの他のハードウェア (gpus) で実行できるようにする必要があります。 .

したがって、Khronos が API を作成したとき、可能な限りシステム/ハードウェアに依存しないようにして、すべてで実行でき、すべての人にとって標準になるようにしました。

GPU メモリに直接書き込み、GPU を直接利用して情報/データを処理する方法を学習する代わりに、API を学習する必要があります。

Vulkan の導入により、(クロノスからも) リリースされたときに状況が異なる可能性がありますが、それがどのように機能するかはわかります。

于 2015-07-03T00:58:35.163 に答える