什么是;即时模式“;在OpenGL中是什么意思?

什么是;即时模式“;在OpenGL中是什么意思?,opengl,Opengl,什么是“即时模式”?给出一个代码示例 什么时候我必须使用即时模式而不是保留模式? 使用每种方法的优缺点是什么?一个“即时模式”的例子是使用glBegin和glEnd,并在它们之间使用glVertex。“立即模式”的另一个示例是将glDrawArrays与客户端顶点数组(即非顶点缓冲区对象)一起使用 您通常永远不会想使用即时模式(可能除了您的第一个“hello world”程序),因为它是不推荐使用的功能,不能提供最佳性能 即时模式不是最佳模式的原因是图形卡直接与程序流链接。驱动程序无法告诉GPU

什么是“即时模式”?给出一个代码示例

什么时候我必须使用即时模式而不是保留模式? 使用每种方法的优缺点是什么?

一个“即时模式”的例子是使用
glBegin
glEnd
,并在它们之间使用
glVertex
。“立即模式”的另一个示例是将
glDrawArrays
与客户端顶点数组(即顶点缓冲区对象)一起使用

您通常永远不会想使用即时模式(可能除了您的第一个“hello world”程序),因为它是不推荐使用的功能,不能提供最佳性能

即时模式不是最佳模式的原因是图形卡直接与程序流链接。驱动程序无法告诉GPU在
glEnd
之前开始渲染,因为它不知道您何时完成数据提交,并且它也需要传输该数据(只有在
glEnd
之后才能执行此操作)。
类似地,对于客户端顶点数组,驱动程序只能在调用
glDrawArrays
时提取数组的副本,并且在执行此操作时必须阻止应用程序。原因是,否则您可以在驱动程序捕获阵列之前修改(或释放)阵列内存。它不能将该操作安排得更早或更晚,因为它只知道数据在某个时间点上确实有效

与此相反,如果使用例如顶点缓冲区对象,则使用数据填充缓冲区并将其交给OpenGL。您的流程不再拥有此数据,因此无法再对其进行修改。司机可以依靠这一事实,并且可以(甚至是推测性地)在公交车空闲时上传数据。
任何稍后的
glDrawArrays
glDrawElements
调用都将进入工作队列并立即返回(在实际完成之前!),因此您的程序会不断提交命令,同时驱动程序会一个接一个地工作。他们也可能不需要等待数据到达,因为驱动程序可以更早地到达。
因此,渲染线程和GPU异步运行,每个组件始终处于繁忙状态,从而产生更好的性能

即时模式的优点是非常简单易用,但是以一种不推荐的方式正确地使用OpenGL也不完全是火箭科学——它只需要很少的额外工作

以下是即时模式下典型的OpenGL“Hello World”代码:

glBegin(GL_三角形);
GL3F(1.0f,0.0f,0.0f);glVertex2f(0.0f,1.0f);
GL3F(0.0f,1.0f,0.0f);glVertex2f(0.87f,-0.5f);
GL3F(0.0f、0.0f、1.0f);glVertex2f(-0.87f,-0.5f);
格伦德();
编辑:
根据常见请求,保留模式下的相同内容看起来有点像这样:

float verts={…};
浮动颜色={…};
静态断言(sizeof(verts)=sizeof(colors),“”);
//本例不需要,但在GL 3.2之后的核心概要文件中是强制性的
GLuint-vao;
glGenVertexArrays(1和vao);
glBindVertexArray(vao);
GLuint-buf[2];
glGenBuffers(2,buf);
//假设位置和位置的布局(位置=0)
//顶点着色器中颜色的布局(位置=1)
//顶点位置
glBindBuffer(GL_数组_BUFFER,buf[0]);
glBufferData(GLU数组缓冲区、大小(顶点)、顶点、GLU静态绘制);
GlenableVertexAttributeArray(0);
glvertexattributepointer(0,3,GL_FLOAT,GL_FALSE,0,0);
//复制/粘贴颜色。。。代码同上。一个真正的、不平凡的程序
//通常两个都使用一个缓冲区——通常使用步幅(第5个参数)来
//GLVertexAttributePointer——假定顶点和颜色数组交错。
//它有点难看,但缓存性能更好(但难看不是这样)
//因为数据是从生成的建模工具加载的,所以这对于实际程序来说很重要
//二进制文件)。
glBindBuffer(GL_数组_BUFFER,buf[1]);
glBufferData(GLU数组缓冲区、大小(颜色)、颜色、GLU静态图);
GlenableVertexAttributeArray(1);
glvertexattributepointer(1,3,GL_FLOAT,GL_FALSE,0,0);
gldrawArray(GL_三角形,0,3);

可运行保留示例

Damon是关键部分,但像我这样的新手会寻找一个完整的可运行的例子

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;
}
从中我们可以看出:

使用着色器时:

  • 顶点和片段着色器程序被表示为C样式字符串,其中包含在CPU上运行的常规C程序中的GLSL语言(
    vertexShaderSource
    fragmentShaderSource

  • 此C程序进行OpenGL调用,将这些字符串编译为GPU代码,例如:

    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"
    
    glColor3f(  1.0f,  0.0f, 0.0f);
    glVertex3f(-0.5f, -0.5f, 0.0f);
    
    并且还将其一个输出
    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调用,明确给出了位置和颜色:

"layout (location = 0) in vec3 position;\n"
"layout (location = 1) in vec3 color;\n"
"out vec3 ourColor;\n"
glColor3f(  1.0f,  0.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
因此,我们理解这代表了一个更受限制的模型,因为位置和颜色不再是内存中任意用户定义的数组,而只是类似Phong模型的输入

在这两种情况下,渲染输出通常直接传送到视频,而不通过CPU传回,尽管可以读取到CPU,例如,如果要将其保存到文件:

大多数“现代”OpenGL教程通常保留模式和GLFW,您可以在以下位置找到许多示例:

非常感谢