Подтвердить что ты не робот

Что означает "немедленный режим" в OpenGL?

Что такое "немедленный режим"? Приведите пример кода.

Когда мне нужно использовать немедленный режим вместо сохраненного режима? Каковы преимущества и недостатки использования каждого метода?

4b9b3361

Ответ 1

Один пример "немедленного режима" использует glBegin и glEnd с glVertex между ними. Другим примером "немедленного режима" является использование glDrawArrays с массивом вершин клиента (т.е. не объект-объект вершин).

Обычно вы никогда не захотите использовать немедленный режим (за исключением, возможно, для вашей первой программы "привет мир" ), потому что это устаревшая функциональность и не обеспечивает оптимальную производительность.

Причина, по которой немедленный режим не является оптимальным, заключается в том, что графическая карта напрямую связана с потоком вашей программы. Драйвер не может сказать, что графический процессор начнет рендеринг перед glEnd, потому что он не знает, когда вы закончите подавать данные, и ему также необходимо перенести эти данные (что можно делать только после glEnd).
Аналогично, с массивом вершин клиента, драйвер может вытащить копию вашего массива только в момент вызова glDrawArrays, и при этом он должен заблокировать ваше приложение. Причина в том, что в противном случае вы могли бы модифицировать (или освобождать) память массива до того, как водитель его захватит. Он не может планировать эту операцию раньше или позже, поскольку он знает только, что данные действительны точно в один момент времени.

В отличие от этого, если вы используете, например, объект буфера вершин, вы заполняете буфер данными и передаете его в OpenGL. Ваш процесс больше не владеет этими данными и поэтому не может его изменять. Драйвер может положиться на этот факт и может (даже спекулятивно) загружать данные всякий раз, когда автобус свободен.
Любой из ваших более поздних вызовов glDrawArrays или glDrawElements просто войдет в рабочую очередь и сразу же вернется (до фактического завершения!), Поэтому ваша программа продолжает отправлять команды, в то время как драйвер работает один за другим. Им также, вероятно, не нужно ждать, пока данные прибудут, потому что водитель уже мог сделать это намного раньше.
Таким образом, рендеринг потоков и графических процессоров выполняется асинхронно, каждый компонент всегда занят, что обеспечивает лучшую производительность.

Непосредственный режим имеет преимущество, заключающееся в том, что он мертв, простое в использовании, но с использованием OpenGL должным образом не устаревшим способом не является точно также и ракетной наукой - для этого требуется очень мало дополнительной работы.

Вот типичный код OpenGL "Hello World" в непосредственном режиме:

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();

Edit:
По общему запросу то же самое в сохраненном режиме будет выглядеть примерно так:

float verts = {...};
float colors = {...};
static_assert(sizeof(verts) == sizeof(colors), "");

// not really needed for this example, but mandatory in core profile after GL 3.2
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

GLuint buf[2];
glGenBuffers(2, buf);

// assuming a layout(location = 0) for position and 
// layout(location = 1) for color in the vertex shader

// vertex positions
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);

// copy/paste for color... same code as above. A real, non-trivial program would
// normally use a single buffer for both -- usually with stride (5th param) to
// glVertexAttribPointer -- that presumes interleaving the verts and colors arrays.
// It somewhat uglier but has better cache performance (ugly does however not
// matter for a real program, since data is loaded from a modelling-tool generated
// binary file anyway).
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); 

Ответ 2

Управляемый сохраненный пример

Damon предоставил ключевые части, но новички вроде меня будут искать полный исполняемый пример.

jneqT.png

#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 = 800, HEIGHT = 600;
/* 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(void) {
    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);

    /* 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 */
    GLint 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);

    GLuint vbo, vao;
    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);

    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
        glClear(GL_COLOR_BUFFER_BIT);
        glUseProgram(shaderProgram);
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, 3);
        glBindVertexArray(0);
        glfwSwapBuffers(window);
    }
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glfwTerminate();
    return EXIT_SUCCESS;
}

В Ubuntu 15.10:

sudo apt-get install libglew-dev libglfw3-dev
gcc main.c -lGL -lGLEW -lglfw

Непосредственный "эквивалент":

glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.5f, -0.5.0f, 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();

Этот пример адаптирован из здесь.

Большинство "современных" OpenGL-руководств обычно сохраняют режим и GLFW, вы найдете много примеров: