1. 程式人生 > >3D Computer Grapihcs Using OpenGL - 10 Color Buffer

3D Computer Grapihcs Using OpenGL - 10 Color Buffer

_array info 點擊切換 arr triangle short 分享圖片 window 沒有

本節我們將嘗試利用三角形制作一個“走馬燈”效果。

技術分享圖片

一個三角形如圖示方式,從左向右依次移動。

先看一下代碼:

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 0 16 // +1.0f, +0.0f, +0.0f,//Color 0 17 // +0.0f, +1.0f, -0.5f,//Vertex 1 18 // +0.0f, +1.0f, +0.0f,//Color 1 19 // +1.0f, -1.0f, +0.5f,//Vertex 2 20 // +0.0f, +0.0f, +1.0f,
//Color 2 21 22 // -1.0f, +1.0f, +0.5f,//Vertex 3 23 // +0.5f, +0.3f, +0.1f,//Color 3 24 // +0.0f, -1.0f, -0.5f,//Vertex 4 25 // +0.1f, +0.4f, +0.2f,//Color 4 26 // +1.0f, +1.0f, +0.5f,//Vertex 5 27 // +1.0f, +0.5f, +0.2f,//Color 5 28 //}; 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