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


82

「イミディエイトモード」とは?コード例を挙げてください。

保持モードの代わりに即時モードを使用する必要があるのはいつですか?それぞれの方法を使用することの長所と短所は何ですか?

回答:


143

「即時モード」の一例は、使用しているglBeginglEndしてglVertexそれらの間インチ 「イミディエイトモード」の別の例はglDrawArrays、クライアント頂点配列で使用することです(つまり、頂点バッファオブジェクトで)で使用することです。

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

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

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

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

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

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


1
デイモン、非常に興味深い比較に感謝します。それは私にはかなり複雑に見えますが、パイプラインを正しく理解すると、それはより明確になると
思い

6
@mallardz:最近のOpenGLで何かをするのははるかに難しいですが、最初のハードルを超えれば(そしてはるかに速く)実際には簡単です。参入障壁が非常に低いため、イミディエイトモードは便利です。私の例では、提供する必要のある頂点シェーダーとフラグメントシェーダー(かなり基本的なもの)がまだありません。実際にコンパイルして機能するものの完全な実行例はかなり長いです。:-)
デイモン

19

実行可能な保持例

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

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

main.c

#include <stdio.h>
#include <stdlib.h>

#define GLEW_STATIC
#include <GL/glew.h>

#include <GLFW/glfw3.h>

#define INFOLOG_LEN 512

static const GLuint WIDTH = 512, HEIGHT = 512;
/* vertex data is passed as input to this shader
 * ourColor is passed as input to the to the fragment shader. */
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[] = {
/*   Positions            Colors */
     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) {
    int immediate = (argc > 1) && argv[1][0] == '1';

    /* Used in !immediate only. */
    GLuint vao, vbo;
    GLint shaderProgram;

    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) {
        float ratio;
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / (float) 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 {
        /* Build and compile shader program. */
        /* Vertex shader */
        GLint vertexShader = glCreateShader(GL_VERTEX_SHADER);
        glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
        glCompileShader(vertexShader);
        GLint success;
        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);
        }
        /* Fragment shader */
        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);
        }
        /* Link shaders */
        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);
        /* Position attribute */
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
        glEnableVertexAttribArray(0);
        /* Color attribute */
        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);

    /* Main loop. */
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    }

    if (!immediate) {
        glDeleteVertexArrays(1, &vao);
        glDeleteBuffers(1, &vbo);
        glDeleteProgram(shaderProgram);
    }
    glfwTerminate();
    return EXIT_SUCCESS;
}

Learn OpenGL私のGitHubアップストリームから適応。

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
# Shader
./main.out
# Immediate
./main.out 1

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

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

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

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

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

    "layout (location = 0) in vec3 position;\n"
    "layout (location = 1) in vec3 color;\n"
    "out vec3 ourColor;\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を保持しています。多くの例は、次の場所にあります。


1
エラーが発生した場合は、stackoverflow.com / questions / 52592309 / …に示すようにERROR::SHADER::VERTEX::COMPILATION_FAILED修正できる可能性があるという報告があります。ただし、再現できません。glfwWindowHint
CiroSantilli郝海东冠事病六四事件法轮功

1
export MESA_GL_VERSION_OVERRIDE=3.3main.out(Debian 8)を実行する前にコマンドを実行することで問題を解決しました。これは、共有した同じ投稿に回答の1つが示されているためです。
Ivanzinho
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.