OpenGL 笔记1 固定管线实例 + 双缓存测试实例
?
欲以此分類來記錄opengl的學習歷程,此為第一篇,所以先來一個固定管線的例子,以及對雙緩存的測試。
?
一、配置環境
寫之前,先進行配置,然后再講內容。
注:第一部分涉及的代碼均忽略。
【環境配置傳送門】
?
二、所需知識
1. opengl程序結構
? ? main函數結構大體上由如下幾個步驟:
1) glutInit(&argc, argv);讀取命令行參數,初始化glut2) glutInitDisplayMode(unsigned int mode);設置顯示模式(或窗口類型) (本節涉及參數如下)GLUT_RGB GLUT_RGBA GLUT_DOUBLE3) glutInitWindowSize(int, int);設置窗口規格4) glutInitWindowPosition(int, int);設置窗口初始位置5) glutCreateWindow(char*);6) if(glewInit()) ....判斷glew是否初始化成功7) init()初始化數據 ,函數體自己寫8) glutDisplayFunc(函數指針);系統自帶的顯示回調宏,在glut每次更新窗口內容的時候自動調用。9) glutMainLoop();無限循環,一直處理窗口消息,如:判斷是否需要進行重繪,然后自動調用glutDisplayFunc()中注冊的函數(即參數)。2. 初始化數據
glGen* ?系列函數,用于OpenGL 分配不同類型的對象名稱。
glBind* ?系列函數,將已分配的對象名稱進行綁定,設定為當前活動對象。
以VBO(Vertex Buffer Object ?頂點緩沖對象)為例,來理解上面兩個函數的理念,其中VBO是一個GLuint對象,即無符號整型。
我們程序員想要操控緩沖區,怎么辦呢,緩沖區位于系統硬件中,對編程人員是不可見的。所以,opengl建立了一個映射機制,以一個GLuint的數據對象來代表某一緩存區。
其中,緩存區為映射的一端,VBO為另一端,我們首先要創建所需的VBO對象,然后通過glGenBuffers(VBO數量,VBO取址);來激活VBO對象作為某一映射的映射端。
因為程序員創建的GLuint對象,系統默認為一個普通的對象,只有通過glGenBuffers(),才能使系統將其認定為緩存區映射的對象。
而glBindBuffer(分配緩沖區類型,已激活的VBO對象);用于建立此映射,將VBO綁定到一個緩沖區,將當前VBO代表的緩沖區作為當前活動對象。爾后的所有關于緩沖區的操作均對當前VBO對象代表的緩沖區進行操作。
?
glBufferData(緩沖區類型,大小,數據,數據的讀寫方式);
剛剛說到VBO映射到一塊緩沖區,但是里面并沒有信息數據,所以要將數據傳到緩沖區中,就是上述函數的作用。
?
我們可以通過glBufferData將一組頂點位置坐標信息傳入到VBO1代表的緩沖區中,然后將頂點的顏色信息傳入到VBO2代表的緩沖區中,當我們渲染的時候,需要顏色信息對顏色信息進行處理加工的時候,我們就通過GLBindBuffer,將VBO2綁定為當前活動對象,反之,同理。
?
上述,以VBO為例講述了相關的一些概念,其他類似的函數同理。
?
3. 渲染
glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* pointer)
| 參數名 | 數值 | 解釋 |
| index | GLuint ? ? 如:0 | 頂點著色器中輸入變量的location值,就是屬性的索引 |
| size | GLint ? ? ? 如:2 | 每個頂點的屬性數量,如:x、y |
| type | GLenum ?如:GL_FLOAT | 頂點屬性變量的數值類型 |
| normalized | GLboolean ?如:GL_FALSE | 設定了頂點數據存儲前是否進行歸一化 |
| stride | GLsizei ? ? 如:0 | 相鄰屬性變量之間間隔的比特長度 |
| pointer | GLvoid* ? ?如:BUFFER_OFFSET(0) | 數據讀取時,開始位置的偏移量 |
通過該函數告訴管線怎樣解析buffer中的數據
?
glDrawArrays(繪制方式,第一個頂點的索引,頂點數量);
void glFlush(void);
強制所有進行中的OpenGL命令立即完成并傳輸到OpenGL服務端處理。這樣就可以保證它們在一定時間內全部完成。
但是,該函數只是強制所有運行中的命令送入服務端而已,它會立即返回,它并不會等待所有的命令完成,而等待確實我們需要做的。。。
glFinish();
它會一直等待所有當前的OpenGL命令立即執行,等待他們全部完成。但是可想而知,它會拖累程序整體性能。
?
三、代碼
1 //配置代碼 2 #if _MSC_VER>=1900 3 #include "stdio.h" 4 _ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned); 5 #ifdef __cplusplus 6 extern "C" 7 #endif 8 FILE* __cdecl __iob_func(unsigned i) { 9 return __acrt_iob_func(i); 10 } 11 #endif /* _MSC_VER>=1900 */ 12 14 #include <iostream> 15 using namespace std; 16 17 //我們需要包含 "val.h" 和 "LoadShaders.h" 18 //如果你按照之前配置環境那樣做了,需要: 19 //#include "vgl.h" 21 22 //我這里是自己將兩個文件放到VS庫目錄里面了,總之,只要正確引用兩個文件即可 23 #include <vgl.h> 26 27 //頂點緩沖對象初始下標、緩沖對象數量、頂點屬性數量、頂點數量 28 enum {Arraybuffers, Numbuffers, AttriNum = 3, VerNum}; 29 30 GLuint buffers[Numbuffers]; //頂點緩沖對象數組 the array of VBOs 31 32 void init(); 33 void Display(); 34 35 int main(int argc, char** argv) 36 { 37 //命令行初始化glut 38 glutInit(&argc, argv); 39 40 //初始化顯示模式 41 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); 42 43 //初始化windows 44 glutInitWindowSize(900, 600); 45 glutInitWindowPosition(20, 20); 46 glutCreateWindow("my work 1"); 47 48 //檢查glew是否就緒 49 if (glewInit()) 50 { 51 cout << "glew didn't go work!" << glewGetErrorString(glewInit()) << endl; 52 exit(EXIT_FAILURE); 53 } 54 55 //初始化數據 56 init(); 57 58 //渲染 59 glutDisplayFunc(Display); 60 61 glutMainLoop(); 62 63 return 0; 64 } 65 66 void init() 67 { 68 //頂點數據 69 GLfloat vertices[VerNum][AttriNum] 70 { 71 { 0.8,0.8,0 }, 72 { -0.1,0,0}, 73 {0.8,-0.8,0}, 74 {-0.8,0,0}, 75 }; 76 77 //創建緩沖器 78 glGenBuffers(Numbuffers, buffers); 79 //綁定緩沖器 80 glBindBuffer(GL_ARRAY_BUFFER, buffers[Arraybuffers]); 81 //向緩沖區傳遞數據 82 glBufferData(GL_ARRAY_BUFFER, sizeof vertices, vertices, GL_STATIC_DRAW); 83 84 //設置清除顏色 85 glClearColor(0, 0, 0, 0); 86 } 87 88 void Display() 89 { 90 //清空顏色緩存 91 glClear(GL_COLOR_BUFFER_BIT); 92 93 //開啟頂點屬性數組 94 glEnableVertexAttribArray(0); 95 96 glBindBuffer(GL_ARRAY_BUFFER, buffers[Arraybuffers]); 97 98 glVertexAttribPointer(0, AttriNum, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); 99 100 //繪制 兩個三角形 101 glColor4f(1, 0, 0, 0.3); //設置顏色 102 glDrawArrays(GL_TRIANGLES, 0, VerNum); 103 glColor4f(0, 0, 1, 0.8); 104 glDrawArrays(GL_TRIANGLES, 1, VerNum); 105 //1. 將繪制好的兩個三角形放到屏幕前面 106 glutSwapBuffers(); 107 108 //在后面的幀緩存中繼續繪制 一個四邊形 邊框 109 glColor4f(1, 0.1, 0.8, 0.0); 110 glDrawArrays(GL_LINE_LOOP, 0, VerNum); 111 112 //2. 將后面的四邊形邊框幀緩存放到屏幕前面 113 glutSwapBuffers(); 114 115 //此時,理論上講,后臺的幀緩存應該為原來繪制的兩個三角形 116 glColor4f(1, 0.1, 0.8, 0.0); 117 //我們在其基礎上,加上邊框 118 glDrawArrays(GL_LINE_LOOP, 0, VerNum); 119 120 //3. 顯示的是兩個三角形+邊框 121 glutSwapBuffers(); 122 123 //禁用頂點屬性數組 這個要最后禁用 124 glDisableVertexAttribArray(0); 125 126 glFlush(); 127 }?
四、效果
標號為1.處得到的效果:(將107-122注釋掉)
標號2.處得到的效果(將114-122注釋)
標號3.處的效果,即將后面幀緩存中的效果添加到原來幀緩存的圖形中得到的效果
?
?
通過這一節的測試,我們真正的看到了雙緩存的工作過程,以及內部數據信息。
?
感謝您的閱讀,生活愉快~
轉載于:https://www.cnblogs.com/lv-anchoret/p/9221504.html
總結
以上是生活随笔為你收集整理的OpenGL 笔记1 固定管线实例 + 双缓存测试实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode之Weekly Cont
- 下一篇: swiper轮播后hover无效问题解决