OpenGL中的“即时模式”是什么意思?
什么是“即时模式”? 给出一个代码示例。
我什么时候必须使用即时模式而不是保留模式? 什么是使用每种方法的优点和缺点?
“即时模式”的一个例子是在他们之间使用glBegin
和glEnd
与glVertex
。 “即时模式”的另一个例子是使用glDrawArrays
与客户机顶点数组(即不是顶点缓冲区对象)。
您通常不会希望使用即时模式(除了可能用于您的第一个“hello world”程序),因为它已被弃用的function,并没有提供最佳的性能。
即时模式不是最佳的原因是graphics卡直接链接到您的程序的stream程。 驱动程序不能告诉GPU在glEnd
之前开始渲染,因为它不知道你什么时候完成提交数据,它也需要传输这些数据(它只能在glEnd
之后进行)。
类似地,对于客户机顶点数组,驱动程序只能在您调用glDrawArrays
的时刻拉取数组的副本,并且在此过程中必须阻止您的应用程序。 原因是否则你可以修改(或释放)arrays的内存之前,驱动程序已经捕获它。 由于只知道数据在某个时间点恰好有效,因此不能提前计划该操作。
与此相反,如果使用顶点缓冲区对象,则用数据填充缓冲区并将其传递给OpenGL。 您的stream程不再拥有这些数据,因此不能再对其进行修改。 司机可以依靠这个事实,并且可以(甚至是推测性地)在公共汽车空闲时上传数据。
你以后的任何一个glDrawArrays
或者glDrawElements
调用都会进入一个工作队列并且立即返回(在实际完成之前),所以你的程序会一直提交命令,同时驱动程序一个接一个地执行。 他们也可能不需要等待数据到达,因为司机可能已经做得更早了。
因此,渲染线程和GPUasynchronous运行,每个组件都是繁忙的,这会产生更好的性能。
即时模式确实具有简单易用的优点,但是,以非弃用的方式正确使用OpenGL也不是精确的火箭科学 – 只需要很less的额外工作。
以下是即时模式下典型的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();
编辑:
按照常见的要求,保留模式下的相同的东西看起来有点像这样:
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's 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);
Runnable保留示例
达蒙提供了关键部分,但像我这样的新人将寻找一个完整的可运行的例子。
#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,你会发现很多例子: