什么是;即时模式“;在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
然后,C程序将包含顶点位置和颜色的数组从CPU提供给GPUstatic const GLchar* fragmentShaderSource = "#version 330 core\n" "in vec3 ourColor;\n"
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
"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,您可以在以下位置找到许多示例: