標籤:rda att 注意 margin 製作 dice 資料 signed data
本節我們將嘗試利用三角形製作一個“走馬燈”效果。
一個三角形示方式,從左向右依次移動。
先看一下代碼:
MyGlWindow.cpp
1 #include <gl\glew.h> 2 #include "MyGlWindow.h" 3 #include <iostream> 4 #include <fstream> 5 6 float triangleWidth = 0.1f; 7 float bytesPerTriangle = sizeof(GLfloat) * 18; 8 uint triangleIndex = 0; 9 uint maxTriangleCount = 20;10 11 void MyGlWindow::sendDataToOpenGL()12 {13 //GLfloat verts[] =14 //{15 // -1.0f, -1.0f, +0.5f,//Vertex 016 // +1.0f, +0.0f, +0.0f,//Color 017 // +0.0f, +1.0f, -0.5f,//Vertex 118 // +0.0f, +1.0f, +0.0f,//Color 119 // +1.0f, -1.0f, +0.5f,//Vertex 220 // +0.0f, +0.0f, +1.0f,//Color 221 22 // -1.0f, +1.0f, +0.5f,//Vertex 323 // +0.5f, +0.3f, +0.1f,//Color 324 // +0.0f, -1.0f, -0.5f,//Vertex 425 // +0.1f, +0.4f, +0.2f,//Color 426 // +1.0f, +1.0f, +0.5f,//Vertex 527 // +1.0f, +0.5f, +0.2f,//Color 528 //};29 30 GLuint vertexBufferID;31 glGenBuffers(1, &vertexBufferID);32 glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);33 glBufferData(GL_ARRAY_BUFFER, maxTriangleCount * bytesPerTriangle, NULL, GL_STATIC_DRAW);34 35 //GLushort indices[] =36 //{37 // 0,1,2,38 // 3,4,5,39 //};40 //GLuint indexBufferID;41 //glGenBuffers(1, &indexBufferID);42 //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);43 //glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);44 45 glEnableVertexAttribArray(0);46 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);47 48 glEnableVertexAttribArray(1);49 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (char*)(sizeof(GLfloat) * 3));50 }51 52 void MyGlWindow::installShaders()53 {54 //未修改,省略...55 }56 57 void MyGlWindow::initializeGL()58 {59 glewInit();60 glEnable(GL_DEPTH_TEST);61 sendDataToOpenGL();62 installShaders();63 }64 65 void MyGlWindow::paintGL()66 {67 glClear(GL_DEPTH_BUFFER_BIT);68 glViewport(0, 0, width(), height());69 //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);70 sendAnotherTriangle();71 glDrawArrays(GL_TRIANGLES, (triangleIndex-1)*3, triangleIndex * bytesPerTriangle);72 }73 74 void MyGlWindow::sendAnotherTriangle()75 {76 if (triangleIndex == maxTriangleCount)77 return;78 GLfloat xVal = -1 + triangleIndex * triangleWidth;79 GLfloat newTriangle[] = 80 {81 xVal, 1.0f, 0.0f,82 1.0f, 0.0f, 0.0f,83 84 xVal + triangleWidth, 1.0f, 0.0f,85 0.0f, 1.0f, 0.0f,86 87 xVal, 0.0f, 0.0f,88 0.0f, 0.0f, 1.0f,89 };90 91 glBufferSubData(GL_ARRAY_BUFFER, bytesPerTriangle * triangleIndex, bytesPerTriangle, newTriangle);92 93 triangleIndex++;94 }95 96 std::string MyGlWindow::ReadShaderCode(const char* fileName)97 {98 //未修改,省略...99 }
MyGlWindow.h
1 #pragma once 2 #include <QtOpenGL\qgl.h> 3 #include <string> 4 class MyGlWindow :public QGLWidget 5 { 6 protected: 7 void sendDataToOpenGL(); 8 void installShaders(); 9 void initializeGL();10 void paintGL();11 std::string ReadShaderCode(const char* fileName);12 void sendAnotherTriangle();13 };
重點看cpp檔案裡的變化。
先定義了幾個變數(其實也可以定義成常量),方便後面使用,他們分別是:
- float triangleWidth = 0.1f 表示三角形的寬度
- float bytesPerTriangle = sizeof(GLfloat) * 18 表示每個三角形包含的頂點資訊資料位元組數,一個三角形使用了3個頂點,每個頂點有6個GLfloat類型資料
- uint triangleIndex = 0 表示當前繪製的三角形的索引
- uint maxTriangleCount = 20 “走馬燈”最多有多少個三角形
此前我們是在sendDataToOpenGL()函數中建立一個verts數組,把所有的資料一次性發送到OpenGL中進行繪製,本次我們需要動態改變繪製的內容,所以就不事先將資料一次性發送了。首先刪除掉sendDataToOpenGL函數中的verts數組。(13-28行)
另外也不需要所以數組了,也把索引數組相關的內容刪除掉。(35-43行以及69行)
33行也做了修改,首先我們要給VertexArrayBuffer分配足夠的空間,所以第二個參數改成了maxTriangleCount * bytesPerTriangle,提供20個三角形需要的空間。而我們在這個階段不需要提供任何資料(後面會講如何提供),所以第三個參數直接給個空值NULL。
在71行繪製Array之前,我們調用了一個新添加的函數sendAnotherTriangle(),這個函數的前半部分(78-89行)是準備資料,準備每次走馬燈要繪製的三角形的資料,由資料內容也能看出來,主要區別就是位置向右移動了。
重點是91行的函數
glBufferSubData(GL_ARRAY_BUFFER, bytesPerTriangle * triangleIndex, bytesPerTriangle, newTriangle);
glBufferSubData 這個OpenGL函數的作用是“部分填充” Array Buffer。可以對比觀察33行的glBufferData(一次性全部填充), 名字只是多了一個Sub,但是兩者的參數還是有些區別的。
- 第一個參數和glBufferData是一樣的,表示設定哪個綁定點的資料。
- 第二個參數是一個繪製的起始位置,因為我們右了一個三角形的索引triangleIndex,所以起始值就是它乘以每個三角形的位元組數。
- 第三個參數表示每個元素的長度,正好使用我們一開始定義的每個三角形的位元組數 bytesPerTriangle
- 第四個參數是資料本身
71行繪製Array Buffer, 注意第二個參數是每個三角形的起始點。
完成後編譯運行,發現畫面並沒有變化,主要原因是畫面沒有重繪,為了啟用重繪,最簡單的辦法就是讓視窗失去焦點和得到焦點,也就是可以在opengl視窗和其他任意視窗之間點擊切換。
但是看到的效果仍然不是我們期望的。效果如下:
這是什麼原因呢?
原因是OpenGL使用了雙重緩衝。一個Front Buffer, 一個Back Buffer。
繪製工作都是在Back Buffer上進行的,以免使用者看到繪製的過程,繪製好以後,會和Front Buffer進行一次交換。這就是為什麼我們看到了似乎有兩副不同的圖在反覆切換。
另外,我們明確指定了每次只繪製一個三角形,但是為什麼之前的三角形都儲存下來了?
原因是我們沒有進行一次“清理”。
找到MyGlWindow.cpp的67行,我們對它進行如下修改:
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
既然要清理Depth Buffer,我們順便使用一個"位或" 運算子把 Color Buffer也添加上。
這樣修改以後,就可以實現"走馬燈"效果了!(效果就不了,動圖太難弄了)
3D Computer Grapihcs Using OpenGL - 10 Color Buffer