OpenGLwikipedia是一种应用程序编程接口(API),它是一种能够对图形硬件设备特性进行访问的软件库。php
一个用来渲染图像的OpenGL程序须要执行的主要操做以下:html
何为光栅化(rasterization)?
将输入图元的数学描述转换为与屏幕位置对应的像素片元,称为光栅化。程序员
一些图形学名词:编程
例1.1 第一个OpenGL程序triangles.cpp
代码(坚果云)
在VS 2013上实现,其中包含了红书官网所提供的源文件中的头文件,以及其中的库文件。运行结果以下:
api
本书所使用的GLUT(OpenGL Utility Toolkit)版本为Freeglut,是原始GLUT库的一个新变种。数组
rendering pipeline,它是一系列数据处理过程,而且将应用程序的数据转换到最终渲染的图像。下图为OpenGL4.3版本的管线。包括:
顶点数据,顶点着色器,细分着色器(细分控制着色器,细分计算着色器),几何着色器,图元设置,剪切,光栅化,片元着色器
缓存
OpenGL须要将全部的数据都保存到缓存对象(buffer object)中。
咱们可使用多种方式建立这样的数据缓存,最经常使用的是glBufferData()wiki。数据结构
Buffer Objects are OpenGL Objects that store an array of unformatted memory allocated by the OpenGL context (aka: the GPU). These can be used to store vertex data, pixel data retrieved from images or the framebuffer, and a variety of other things.
--from wikiide
当将缓存初始化完毕后,经过调用OpenGL的一个绘制命令来请求渲染几何图元。glDrawArrays()wiki就是一个经常使用的绘制命令。OpenGL的绘制一般就是将顶点数据传输到OpenGL服务端。函数
对于绘制命令传输的每一个顶点,OpenGL都会调用一个顶点着色器来处理顶点相关的数据。
只是将数据复制并传递到下一个着色阶段,叫作传递着色器(pass-through shader)。
一般来讲,一个复杂的应用程序可能包含许多顶点着色器,但在同一时刻只能有一个顶点着色器起做用。
顶点着色器处理每一个顶点的关联数据以后,若是同时激活了细分着色器,那么它将进一步处理这些数据。(第9章介绍)
细分着色器阶段会用到两个着色器来分别管理Patch数据并产生最终的形状。
第10章介绍。
图元装配将顶点及相关的集合图元之间组织起来,准备下一步剪切和光栅化操做。
顶点可能落在视口(viewport)以外,此时与顶点相关的图元会作出改动,以保证相关的像素不会在视口外绘制。剪切(clipping)由OpenGL自动完成。
将更新后的图元(primitive)传递到光栅化单元,生成对应的片元(fragment)。咱们将一个片元是为一个“候选的像素”。也就是能够放置在帧缓存(framebuffer)中的像素,可是它也可能被最终剔除,再也不更新对应的像素位置。以后两个阶段将会执行片元的处理。
最后一个能够经过编程控制屏幕上显示颜色的阶段。在Fragment Shader阶段中,咱们使用着色器计算片元的最终颜色和它的深度值。
顶点着色器与片元着色器之间的区别:
顶点着色(包括细分和几何着色)决定了一个图元应该位于屏幕的什么位置,而片元着色使用这些信息来决定某个片元的颜色应该是什么。
在这个阶段会使用深度测试(depth test,或者一般也称为z-bufffering)和模板测试(stencil test)的方式来决定一个片元是不是可见的。
int main (int argc, char ** argv) { glutInit (&argc, argv); glutInitDisplayMode (GLUT_RGBA); glutInitWindowSize (512, 512); glutInitContextVersion (4, 3); glutInitContextProfile (GLUT_CORE_PROFILE); glutCreateWindow (argv[0]); glewExperimental = GL_TRUE; if (glewInit ()) { cerr << "Unable to initialize GLEW ... exiting..." << endl; exit (EXIT_FAILURE); } init (); glutDisplayFunc (display); glutMainLoop ();
前面的6行使用GLUT(OpenGL Utility Toolkit)初始化和打开了一个渲染用的窗口:
到这,完成了使用OpenGL以前的所有设置工做。以后init()函数初始化OpenGL相关的全部数据。在以后完成渲染工做。
void init (void) { glGenVertexArrays (NumVAOs, VAOs); glBindVertexArray (VAOs[Triangles]); GLfloat vertices[NumVertices][2] = { { -0.90, -0.90 }, // Triangle 1 { 0.85, -0.90 }, { -0.90, 0.85 }, { 0.90, -0.85 }, // Triangle 2, { 0.90, 0.90 }, { -0.85, 0.90 } }; glGenBuffers (NumBuffers, Buffers); glBindBuffer (GL_ARRAY_BUFFER, Buffers[ArrayBuffer]); glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW); ShaderInfo shaders[] = { { GL_VERTEX_SHADER, "triangles.vert" }, { GL_FRAGMENT_SHADER, "triangles.frag" }, { GL_NONE, NULL } }; GLuint program = LoadShaders (shaders); glUseProgram (program); glVertexAttribPointer (vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET (0)); glEnableVertexAttribArray (vPosition); }
void glGenVertexArrays(GLsizei n, GLuint *arrays);
n
Specifies the number of vertex array object names to generate.
arrays
Specifies an array in which the generated vertex array object names are stored.
The names returned in arrays are marked as used, for the purposes of glGenVertexArrays only, but they acquire state and type only when they are first bound.
不少OpenGL命令都是glGen的形式,它们负责分配不一样类型的OpenGL对象的名称。这里的名称相似C语言中的指针变量,必须分配内存而且用名称引用它以后,名称才有意义。在OpenGL中,这个分配的机制叫作绑定对象(bind an object)。这经过一系列glBind形式的OpenGL函数集合去实现。
glBindVertexArray (VAOs[Triangles])建立一个顶点数组对象,并与其名称(VAOs[Triangles])关联起来。
void glBindVertexArray(GLuint array);
array
Specifies the name of the vertex array to bind.
(未使用)glDeleteVertexArrays(),当咱们完成对顶点数组对象的操做以后,能够调用此函数将它(们)释放。
void glDeleteVertexArrays(GLsizei n, const GLuint *arrays);
n
Specifies the number of vertex array objects to be deleted.
arrays
Specifies the address of an array containing the n names of the objects to be deleted.
(未使用)glIsVertexArray(),检查某个名称是否已经关联到一个顶点数组对象了。
GLboolean glIsVertexArray(GLuint array);
array
Specifies a value that may be the name of a vertex array object.
顶点数组对象(VAO)负责保存一系列顶点的数据。这些数据保存到缓存对象(Buffer Object)中,而且由当前绑定的顶点数组对象管理。
官方解释:A Vertex Array Object (VAO) is an OpenGL Object that stores all of the state needed to supply vertex data (with one minor exception noted below). It stores the format of the vertex data as well as the Buffer Objects providing the vertex data arrays.
glGenBuffers (NumBuffers, Buffers) 返回NumBuffers个当前未使用的缓存对象名称到数组Buffers中。(名称不必定是连续的整型数据)
void glGenBuffers(GLsizei n, GLuint * buffers);
n
Specifies the number of buffer object names to be generated.
buffers
Specifies an array in which the generated buffer object names are stored.
No buffer objects are associated with the returned buffer object names until they are first bound by calling glBindBuffer.
glBindBuffer (GL_ARRAY_BUFFER, Buffers[ArrayBuffer])在分配缓存的名称以后,就能够调用glBindBuffer()来绑定它们了。因为OpenGL中有不少种不一样类型的缓存对象,所以绑定一个缓存时,须要指定它所对应的类型。此例中因为是将顶点数据保存到缓存中(故为顶点缓存对象VBO),所以使用GL_ARRAY_BUFFER类型。
void glBindBuffer(GLenum target, GLuint buffer);
target
Specifies the target buffer object. The symbolic constant must be GL_ARRAY_BUFFER, GL_ATOMIC_COUNTER_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_DRAW_INDIRECT_BUFFER, GL_DISPATCH_INDIRECT_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_QUERY_BUFFER, GL_SHADER_STORAGE_BUFFER, GL_TEXTURE_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, or GL_UNIFORM_BUFFER.
buffer
Specifies the name of a buffer object.
When a buffer object is bound to a target, the previous binding for that target is automatically broken.
(未使用)glDeleteBuffers(),全部的缓存对象均可以使用glDeleteBuffers()直接释放。
void glDeleteBuffers(GLsizei n, const GLuint * buffers);
n
Specifies the number of buffer objects to be deleted.
buffers
Specifies an array of buffer objects to be deleted.
glIsBuffer(),使用此函数来判断一个整数值是否为缓存对象的名称。
GLboolean glIsBuffer(GLuint buffer);
buffer
Specifies a value that may be the name of a buffer object.
A name returned by glGenBuffers, but not yet associated with a buffer object by calling glBindBuffer, is not the name of a buffer object.
glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW),初始化顶点缓存对象以后(VBO),咱们须要把顶点数据传输到缓存对象中。它主要有两个任务:分配顶点数据所需的存储空间(内存中),而后将数据从应用程序的数组中拷贝到OpenGL服务端的内存中。
void glBufferData(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage);
target
Specifies the target buffer object. The symbolic constant must be GL_ARRAY_BUFFER, GL_ATOMIC_COUNTER_BUFFER, GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, GL_DRAW_INDIRECT_BUFFER, GL_DISPATCH_INDIRECT_BUFFER, GL_ELEMENT_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, GL_QUERY_BUFFER, GL_SHADER_STORAGE_BUFFER, GL_TEXTURE_BUFFER, GL_TRANSFORM_FEEDBACK_BUFFER, or GL_UNIFORM_BUFFER.
size
Specifies the size in bytes of the buffer object's new data store.
data
Specifies a pointer to data that will be copied into the data store for initialization, or NULL if no data is to be copied.
usage
Specifies the expected usage pattern of the data store. The symbolic constant must be GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY.
例1.2 triangles.cpp对应的顶点着色器:triangles.vert
#version 430 core layout (location = 0) in vec4 vPosition; void main () { gl_Position = vPosition; }
事实上这就是咱们所说的传递着色器(pass-through shader)。它只负责将输入数据拷贝到输出数据中。
第一行
#version 430 core
指定了OpenGL着色语言的版本。每一个着色器的第一行都应该设置#version,不然就会假设使用“110”版本。
下一步,分配了一个着色器变量,着色器变量是着色器与外部世界的联系所在。着色器并不知道本身的数据从哪里来,它只是在每次运行时直接获取数据对应的输入变量。而咱们必须本身完成着色管线的装配,而后才能够将应用程序中的数据与不一样的OpenGL着色阶段相互关联。
layout (location = 0) in vec4 vPosition;
最后,在着色器的main()函数中实现它的主体部分。对于这个着色器而言,它所实现的就是将输入的顶点位置(存在vPosition中)复制到顶点着色器的指定输出位置gl_Position。
例1.3 triangles.cpp对应的片元着色器:triangles.frag
@version 430 core out vec4 fColor void main() { fColor = vec4(0.0, 0.0, 1.0, 1.0); }
init()中的最后两个函数指定了顶点着色器的变量与咱们存储在缓存对象中的数据的关系。这也就是咱们所说的着色管线的装配过程,即将程序与着色器之间,以及不一样着色阶段之间的数据通道链接起来。
glVertexAttribPointer (vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET (0));
为了输入顶点着色器所需的数据,也就是OpenGL将要处理的全部顶点数据,须要在着色器中声明一个in变量,而后使用glVertexAttribPointer()将它关联到一个顶点属性数组。glVertexAttribPointer()是一个很是灵活的命令,只要内存中的数据是规范组织的(保存在一个连续的数组中,不使用其余基于节点的容器,如链表),咱们就可使用glVertexArrtibPointer()告诉OpenGL直接从内存中获取数据。
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * pointer);
void glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);
void glVertexAttribLPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);
index
Specifies the index of the generic vertex attribute to be modified.
size
Specifies the number of components per generic vertex attribute. Must be 1, 2, 3, 4. Additionally, the symbolic constant GL_BGRA is accepted by glVertexAttribPointer. The initial value is 4.
type
Specifies the data type of each component in the array. The different functions take different values.
glVertexAttribPointer and glVertexAttribIPointer both take: GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, and GL_UNSIGNED_INT
glVertexAttribPointer also can take: GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, GL_FIXED, GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV, and GL_UNSIGNED_INT_10F_11F_11F_REV.
glVertexAttribLPointer takes only GL_DOUBLE.
The initial value is GL_FLOAT.
normalized
For glVertexAttribPointer, specifies whether fixed-point data values should be normalized (GL_TRUE) or converted directly as fixed-point values (GL_FALSE) when they are accessed.
stride
Specifies the byte offset between consecutive generic vertex attributes. If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.
pointer
Specifies a offset of the first component of the first generic vertex attribute in the array in the data store of the buffer currently bound to the GL_ARRAY_BUFFER target. The initial value is 0.
glEnableVertexAttribArray (vPosition);
咱们经过glEnableVertexAttribArray()来启用顶点属性数组。glVertexAttribPointer()初始化的属性数组指针索引传入这个函数。
void glEnableVertexAttribArray(GLuint index);
void glDisableVertexAttribArray(GLuint index);
index
Specifies the index of the generic vertex attribute to be enabled or disabled.
void display (void) { glClear (GL_COLOR_BUFFER_BIT); glBindVertexArray (VAOs[Triangles]); glDrawArrays (GL_TRIANGLES, 0, NumVertices); glFlush (); }
glClear(GL_COLOR_BUFFER_BIT),清除帧缓存的数据。
void glClear(GLbitfield mask);
mask
Bitwise OR of masks that indicate the buffers to be cleared. The three masks are GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT.
(未使用)glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha),设置当前使用的清除颜色值,用于RGBA模式下对颜色缓存的清除工做。
清除颜色自己也是OpenGL状态机制的一个例子,它的数值会一直保留在当前OpenGL环境当中。
OpenGL有一个庞大的状态量列表。当建立一个新的OpenGL环境时,全部的状态量都会被初始化为默认值。由于OpenGL会保留全部更改的状态值,因此咱们能够减小设置状态数值的次数。
故而,在设置清除颜色为白色时,能够在display()函数中调用glClearColor(1, 1, 1, 1),也能够在init()函数中调用glClearColor(1, 1, 1, 1),后者效率更高,由于能够避免冗余的状态切换。
glBindVertexArray (VAOs[Triangles]),选择做为顶点数据使用的顶点数组。咱们可使用这个函数来切换程序中保存的多个顶点数据对象集合。
glDrawArrays (GL_TRIANGLES, 0, NumVertices),使用当前绑定的顶点数组元素来创建一系列的几何图元。实现顶点数据向OpenGL管线的传输。
glDrawArrays: render primitives from array data
void glDrawArrays(GLenum mode, GLint first, GLsizei count);
mode
Specifies what kind of primitives to render. Symbolic constants GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_LINE_STRIP_ADJACENCY, GL_LINES_ADJACENCY, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES, GL_TRIANGLE_STRIP_ADJACENCY, GL_TRIANGLES_ADJACENCY and GL_PATCHES are accepted.
first
Specifies the starting index in the enabled arrays.
count
Specifies the number of indices to be rendered.
glFlush (),强制全部进行中的OpenGL命令当即完成并传输到OpenGL服务端处理。
glFlush: force execution of GL commands in finite time
void glFlush(void);
(未使用)glFinish(),会等待全部当前的OpenGL操做完成。而glFlush()则只是强制全部运行中的命令送入OpenGL服务端而已,不会等待全部的命令完成。所以当咱们须要了解OpenGL是在是么时候完成操做的时候使用glFinish()。
glFinish: block until all GL execution is complete
void glFinish(void);
glFinish does not return until the effects of all previously called GL commands are complete. Such effects include all changes to GL state, all changes to connection state, and all changes to the frame buffer contents.
(未使用)glEnable(),glDisable(),启用或禁用OpenGL的操做模式。
glEnable: enable or disable server-side GL capabilities
void glEnable(GLenum cap);
void glDisable(GLenum cap);
cap
Specifies a symbolic constant indicating a GL capability.
(未使用)glIsEnabled(),返回是否启用指定模式。
glIsEnabled, glIsEnabledi: test whether a capability is enabled
GLboolean glIsEnabled(GLenum cap);
GLboolean glIsEnabledi(GLenum cap, GLuint index);
cap
Specifies a symbolic constant indicating a GL capability.
index
Specifies the index of the capability.
相关连接: