まず、OpenGL はステート マシンであることを知っておく必要があります。つまり、(SFML によって行われる) OpenGL コンテキストの作成を除けば、初期化などはありません!
私は暗記が苦手なので、
これはいい…</p>
「なぜ私たちはこれをしているのですか?」に対する答えが常に必要です。
これは素晴らしいです!
glBegin() と glEnd() で何かを描画し始める前に、OpenGL (純粋な OpenGL のみ、バックグラウンド ライブラリとして SFML を使用していますが、それは実際には問題ではありません) に何を定義する必要があるかを誰かに説明してもらえますか?
すでに述べたように、OpenGL はステート マシンです。つまり、基本的には、状態の設定と操作の実行という 2 種類の呼び出しを行うことができます。
たとえば、フラグが設定されglClearColor
た の呼び出し時に、アクティブなフレームバッファ カラーをクリアするために使用されるクリア カラーの状態変数を設定します。深度値 ( flag to ) にも同様の関数が存在します。glClear
GL_COLOR_BUFFER_BIT
glClearDepth
GL_DEPTH_BUFFER_BIT
glClear
glBegin
廃止された OpenGL の即時モードにglEnd
属します。したがって、それらを学ぶ理由はほとんどありません。代わりに頂点配列を使用する必要があります。頂点バッファー オブジェクトを使用することをお勧めします。
しかし、次のようになります: glBegin
OpenGL を、 のパラメータとして選択された種類のプリミティブのジオメトリを描画する必要がある状態に設定しますglBegin
。GL_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();