運行結果:
(圓錐面)
(拋物面)
(馬鞍面)
其中的做法是:從頂部看上去就是一個平面網格、每個點的 z、x的位置都是程序細分出來的(指定起始、結束、步長)、比較固定、但高度 y 的計算使用 用戶指定的函數去計算
把每個頂點的信息傳入 vbo、再計算出每個三角面片的索引號、傳入ebo、最后glDrawElement()進行繪制!
由于這是opengl而不是高等數學、所以y應該是向上的、這些細節在生成點的時候可以交換一下變量從而得到解決
同樣應該把這種模型封裝到類里。
相關的成員變量:
Xs:X坐標的start
Xe:X坐標的end
Y同理
Fxy:用 stl 的方法傳遞函數、而不是用函數指針
pointCount:指出有多少個頂點、用于給vbo傳數據
totalIndices:指出ebo有多少個索引元素、繪制時有用
Q:一列有多少個點
P:一行有多少個點


傳遞函數到類內、并保存起來的的代碼:
void setFunction(std::function<float(float, float)> fxy) {
this->Fxy = fxy;
this->isFunctionInit = true;
}
計算PQ的代碼: 可以先帶個小的數驗算一下: 比如 從【-1,1】、delta = 0.5,那就是 -1, -0.5 , 0 ,0.5, 1 五個點、確實等于 ((1-(-1))/0.5)+1
總的點數那么肯定是 Q*P 了
Q = ((Ye - Ys) / delta ) + 1 ;
P = ((Xe - Xs) / delta) + 1; pointCount = Q * P;
接下來就可以程序化生成點和索引號了:
生成點的代碼是從第一列開始、然后每列處理完了就進行下一列
所以可以知道、這個網格的左上角的點是第一個被處理的、它的邏輯坐標是(0,0)、ebo 要索引 vbo 的下標是 0
從而 定義一個 index宏 表示網格上 以 x,y 為坐標(不是實際的浮點數坐標、而是從 j ∈ [0...Q - 1], i ∈ [0...P - 1]的邏輯坐標)對應的點在 vbo 內的索引號
比如: (0,0)--> 0 : 左上角的點是第0個點
(1,0)--> col = Q 左上角的那個點的右鄰居確實索引是 Q、 因為第一列點的索引是從 [0....Q-1] (共Q個點)
總共的索引數是 (P-1)*(Q-1)* 6 ,因為如果有 P 個點、那么就有 P -1 個間距、從而整個網只有 (P-1)*(Q-1)個正方塊、我們用三角形再切開每個面、需要兩個三角形、每個三角形又有三個頂點必須指定。
從這張圖可以清楚分析出哪幾個點應該是一個三角面片

后面生成VAO、VBO、EBO的代碼就不用多說了!!注意思考好到底開多大的顯存!這里很容易算錯
1 #define index(x,y,col) (x)*(col)+(y) 2 3 void FuncMesh::genMesh() { 4 if (this->isFunctionInit == false) { 5 return; 6 } 7 8 auto points = new Vector3[pointCount]; 9 size_t id1 = 0; 10 for (float curX = Xs; curX <= Xe ; curX += deltaH) 11 { 12 for (float curY = Ys; curY <= Ye ; curY+= deltaH) 13 { 14 Vector3 v3; 15 v3.x = curX; 16 v3.z = curY; 17 v3.y = Fxy(curX, curY); 18 points[id1] = v3; 19 id1++; 20 } 21 } 22 totalIndices = (P-1) * (Q-1) * 6; 23 GLuint* eboArr = new GLuint[totalIndices];
24 for (size_t i = 0; i <= P-2; i++) 26 { 27 for (size_t j = 0; j <= Q-2; j++) 28 { 29 eboArr[k++] = index(i, j, Q); 30 eboArr[k++] = index(i+1, j, Q); 31 eboArr[k++] = index(i, j+1, Q); 32 33 eboArr[k++] = index(i, j+1, Q); 34 eboArr[k++] = index(i+1, j, Q); 35 eboArr[k++] = index(i+1, j+1, Q); 36 } 37 } 38 GLuint vbo; 39 GLuint ebo; 40 41 42 glGenVertexArrays(1,&vao); 43 glBindVertexArray(vao); 44 45 glGenBuffers(1, &vbo); 46 glBindBuffer(GL_ARRAY_BUFFER, vbo); 47 glBufferData(GL_ARRAY_BUFFER, pointCount*(sizeof(Vector3)), points, GL_STATIC_DRAW); 48 glEnableVertexAttribArray(0); 49 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 50 51 glGenBuffers(1, &ebo); 52 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); 53 glBufferData(GL_ELEMENT_ARRAY_BUFFER, totalIndices * sizeof(GLuint), eboArr, GL_STATIC_DRAW); 54 55 glBindVertexArray(0); 56 57 }
vshader的話、就用一個簡單的MVP矩陣變換、
fshader的話、就用一個簡單的輸出單一顏色即可
順便說一下VS中配置相對路徑從而引用第三方庫到底怎么寫:
比如我的目錄:

--》包含

Project1中是:

這個黃色箭頭指向的文件夾里有vs的項目文件:

third中是:

那么、我們在VS中要配置附加包含目錄和附加庫目錄、其實就是相對那個 vxproj 進行配置的!
右擊---》屬性

..\..\ 表示往父級后退兩步、從哪里開始退呢?就是從 vxproj (一個solution里可能有多個project、以目前右擊的那個為準)所在的那個文件夾處后退兩步、可以看到這確實會退到只有 {Project1、third} 這兩個文件夾的那個文件夾、然后再步進到third中就行了!

完整的工程下載(自帶一堆三方庫):
鏈接:https://pan.baidu.com/s/1KWGrK8yfddlHCVolBWn2sA
提取碼:bby7
浙公網安備 33010602011771號