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.
相關連接: