OpenGLで「イミディエイトモード」とはどういう意味ですか?



What Doesimmediate Modemean Opengl



解決:

「イミディエイトモード」の一例は、glBeginとglEnd withそれらの間のglVertex。 「イミディエイトモード」の別の例は、クライアント頂点配列を持つglDrawArrays(つまり、 いいえ 頂点バッファオブジェクト)。

即時モードは非推奨の機能であり、最適なパフォーマンスを提供しないため、通常は(おそらく最初の「helloworld」プログラムを除いて)即時モードを使用することはありません。



イミディエイトモードが最適でない理由は、グラフィックカードがプログラムのフローに直接リンクされているためです。ドライバーは、前にレンダリングを開始するようにGPUに指示できませんglEnd、データの送信がいつ終了するかわからないため、そのデータも転送する必要があります(これは可能です) それだけ 後に行うglEnd)。
同様に、クライアント頂点配列の場合、ドライバーは呼び出した瞬間にのみ配列のコピーをプルできますglDrawArraysであり、そうしている間はアプリケーションをブロックする必要があります。その理由は、そうでなければ、ドライバがアレイをキャプチャする前に、アレイのメモリを変更(または解放)する可能性があるためです。データが正確にある時点で有効であることがわかっているだけなので、その操作を以前または後でスケジュールすることはできません。

それとは対照的に、たとえば頂点バッファオブジェクトを使用する場合は、バッファにデータを入力してOpenGLに渡します。プロセスはこのデータを所有しなくなったため、データを変更できなくなりました。ドライバーはこの事実に頼ることができ、バスが空いているときはいつでも(投機的にさえ)データをアップロードすることができます。
あなたの後のいずれかglDrawArraysまたはglDrawElementsの呼び出しは、ワークキューに入り、すぐに(実際に終了する前に!)戻るため、プログラムはコマンドを送信し続けると同時に、ドライバーが1つずつ動作します。また、ドライバーはすでにはるかに早い段階でデータが到着する可能性があるため、データが到着するのを待つ必要はないでしょう。
したがって、レンダリングスレッドとGPUは非同期で実行され、すべてのコンポーネントが常にビジー状態になり、パフォーマンスが向上します。



イミディエイトモードには、非常に簡単に使用できるという利点がありますが、OpenGLを非推奨ではない方法で適切に使用することも、厳密にはロケット科学ではありません。余分な作業はほとんど必要ありません。

即時モードでの典型的なOpenGLの「HelloWorld」コードは次のとおりです。

glBegin(GL_TRIANGLES); glColor3f(1.0f、0.0f、0.0f); glVertex2f(0.0f、1.0f); glColor3f(0.0f、1.0f、0.0f); glVertex2f(0.87f、-0.5f); glColor3f(0.0f、0.0f、1.0f); glVertex2f(-0.87f、-0.5f); glEnd();

編集:
一般的な要求により、保持モードでの同じことは次のようになります。



float verts = {...};フロートカラー= {...}; static_assert(sizeof(verts)== sizeof(colors)、 ''); //この例では実際には必要ありませんが、GL 3.2 GLuintvao以降のコアプロファイルでは必須です。 glGenVertexArrays(1、&vao); glBindVertexArray(vao); GLuint buf [2]; glGenBuffers(2、buf); //頂点シェーダーの位置にlayout(location = 0)、//色にlayout(location = 1)を想定//頂点の位置glBindBuffer(GL_ARRAY_BUFFER、buf [0]); glBufferData(GL_ARRAY_BUFFER、sizeof(verts)、verts、GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0、3、GL_FLOAT、GL_FALSE、0、0); //色をコピーして貼り付けます...上記と同じコード。実際の重要なプログラムは、通常、両方に単一のバッファーを使用します。通常は、verts配列とcolors配列のインターリーブを前提とする// glVertexAttribPointerへのストライド(5番目のパラメーター)を使用します。 //多少醜いですが、キャッシュパフォーマンスが向上します(ただし、データはモデリングツールで生成されたバイナリファイルから//とにかくロードされるため、実際のプログラムでは//醜いことは問題ではありません)。 glBindBuffer(GL_ARRAY_BUFFER、buf [1]); glBufferData(GL_ARRAY_BUFFER、sizeof(colors)、colors、GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1、3、GL_FLOAT、GL_FALSE、0、0); glDrawArrays(GL_TRIANGLES、0、3); 

実行可能な保持された例

デイモンは重要な部分を提供しましたが、私のような初心者は完全に実行可能な例を探しています。

ここに画像の説明を入力してください

main.c

#include #include #define GLEW_STATIC #include #include #define INFOLOG_LEN 512 static const GLuint WIDTH = 512、HEIGHT = 512; / *頂点データはこのシェーダーへの入力として渡されます* ourColorはフラグメントシェーダーへの入力として渡されます。 * / static const GLchar * VertexShaderSource = '#version 330 core  n''layout(location = 0)in vec3 position;  n''layout(location = 1)in vec3 color;  n''out vec3 ourColor;  n '' void main(){ n '' gl_Position = vec4(position、1.0f);  n '' ourColor = color;  n ''}  n '; static const GLchar * FragmentShaderSource = '#version 330 core  n''in vec3 ourColor;  n''out vec4 color;  n''void main(){ n''color = vec4(ourColor、1.0f);  n ''}  n '; GLfloat vertices [] = {/ *位置の色* / 0.5f、-0.5f、0.0f、1.0f、0.0f、0.0f、-0.5f、-0.5f、0.0f、0.0f、1.0f、0.0f 、0.0f、0.5f、0.0f、0.0f、0.0f、1.0f}; int main(int argc、char ** argv){intimmediate =(argc> 1)&& argv [1] [0] == '1'; / *!immediateでのみ使用されます。 * / GLuint vao、vbo; GLintシェーダープログラム; glfwInit(); GLFWwindow * window = glfwCreateWindow(WIDTH、HEIGHT、__ FILE __、NULL、NULL); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; glewInit(); glClearColor(0.0f、0.0f、0.0f、1.0f); glViewport(0、0、WIDTH、HEIGHT); if(immediate){フロート比; int幅、高さ; glfwGetFramebufferSize(window、&width、&height);比率=幅/(フロート)高さ; glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-ratio、ratio、-1.f、1.f、1.f、-1.f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBegin(GL_TRIANGLES); glColor3f(1.0f、0.0f、0.0f); glVertex3f(-0.5f、-0.5f、0.0f); glColor3f(0.0f、1.0f、0.0f); glVertex3f(0.5f、-0.5f、0.0f); glColor3f(0.0f、0.0f、1.0f); glVertex3f(0.0f、0.5f、0.0f); glEnd(); } else {/ *シェーダープログラムをビルドしてコンパイルします。 * / / *頂点シェーダー* / GLintvertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader、1、&vertexShaderSource、NULL); glCompileShader(vertexShader); GLintの成功; GLchar infoLog [INFOLOG_LEN]; glGetShaderiv(vertexShader、GL_COMPILE_STATUS、&success); if(!success){glGetShaderInfoLog(vertexShader、INFOLOG_LEN、NULL、infoLog); printf( 'ERROR :: SHADER :: VERTEX :: COMPILATION_FAILED  n%s  n'、infoLog); } / *フラグメントシェーダー* / GLint FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader、1、&fragmentShaderSource、NULL); glCompileShader(fragmentShader); glGetShaderiv(fragmentShader、GL_COMPILE_STATUS、&success); if(!success){glGetShaderInfoLog(fragmentShader、INFOLOG_LEN、NULL、infoLog); printf( 'ERROR :: SHADER :: FRAGMENT :: COMPILATION_FAILED  n%s  n'、infoLog); } / *リンクシェーダー* / shaderProgram = glCreateProgram(); glAttachShader(shaderProgram、vertexShader); glAttachShader(shaderProgram、fragmentShader); glLinkProgram(shaderProgram); glGetProgramiv(shaderProgram、GL_LINK_STATUS、&success); if(!success){glGetProgramInfoLog(shaderProgram、INFOLOG_LEN、NULL、infoLog); printf( 'ERROR :: SHADER :: PROGRAM :: LINKING_FAILED  n%s  n'、infoLog); } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); glGenVertexArrays(1、&vao); glGenBuffers(1、&vbo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER、vbo); glBufferData(GL_ARRAY_BUFFER、sizeof(vertices)、vertices、GL_STATIC_DRAW); / *位置属性* / glVertexAttribPointer(0、3、GL_FLOAT、GL_FALSE、6 * sizeof(GLfloat)、(GLvoid *)0); glEnableVertexAttribArray(0); / *色属性* / glVertexAttribPointer(1、3、GL_FLOAT、GL_FALSE、6 * sizeof(GLfloat)、(GLvoid *)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glBindVertexArray(0); glUseProgram(shaderProgram); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES、0、3); glBindVertexArray(0); } glfwSwapBuffers(window); / *メインループ。 * / while(!glfwWindowShouldClose(window)){glfwPollEvents(); } if(!immediate){glDeleteVertexArrays(1、&vao); glDeleteBuffers(1、&vbo); glDeleteProgram(shaderProgram); } glfwTerminate(); EXIT_SUCCESSを返します。 }

私のGitHubアップストリームであるLearnOpenGLから適応。

Ubuntu20.04でコンパイルして実行します。

sudo apt install libglew-dev libglfw3-dev gcc -ggdb3 -O0 -std = c99 -Wall -Wextra -pedantic -o main.out main.c -lGL -lGLEW -lglfw#シェーダー./main.out#即時./main .out 1

それから、次のことがわかります。

シェーダーを使用する場合:

  • 頂点シェーダープログラムとフラグメントシェーダープログラムは、GLSL言語を含むCスタイルの文字列として表されています(VertexShaderSourceおよびFragmentShaderSource)CPU上で実行される通常のCプログラム内

  • このCプログラムは、これらの文字列をGPUコードにコンパイルするOpenGL呼び出しを行います。例:

    glShaderSource(fragmentShader、1、&fragmentShaderSource、NULL); glCompileShader(fragmentShader);
  • シェーダーは期待される入力を定義し、CプログラムはGPUコードへのメモリへのポインターを介してそれらを提供します。たとえば、フラグメントシェーダーは、期待される入力を頂点の位置と色の配列として定義します。

    'vec3位置のレイアウト(位置= 0);  n''vec3カラーのレイアウト(位置= 1);  n' '出力vec3ourColor;  n'

    また、その出力の1つを定義します色の配列としてのourColorは、フラグメントシェーダーへの入力になります。

    static const GLchar * FragmentShaderSource = '#version 330 core  n''in vec3 ourColor;  n'

    次に、Cプログラムは、CPUからGPUへの頂点の位置と色を含む配列を提供します。

    glBufferData(GL_ARRAY_BUFFER、sizeof(vertices)、vertices、GL_STATIC_DRAW);

ただし、シェーダー以外の直接の例では、位置と色を明示的に指定するマジックAPI呼び出しが行われていることがわかります。

glColor3f(1.0f、0.0f、0.0f); glVertex3f(-0.5f、-0.5f、0.0f);

したがって、位置と色はメモリ内の任意のユーザー定義配列ではなく、Phongのようなモデルへの入力にすぎないため、これははるかに制限されたモデルを表すことを理解しています。

どちらの場合も、レンダリングされた出力は通常、CPUを経由せずにビデオに直接送られますが、CPUに読み取ることは可能です。それらをファイルに保存したい場合:GLUT / OpenGLを使用してファイルにレンダリングする方法は?

ほとんどの「最新の」OpenGLチュートリアルは通常保持モードとGLFWであり、多くの例が次の場所にあります。

  • https://github.com/JoeyDeVries/LearnOpenGL
  • https://github.com/opengl-tutorials/ogl
  • https://github.com/capnramses/antons_opengl_tutorials_book
  • https://github.com/Overv/Open.GL/tree/master/content/code
  • https://github.com/tomdalling/opengl-series