天天看點

opengl--頂點數組和緩沖區對象一、OpenGL頂點數組二、Opengl緩沖區對象VAO三、幀緩沖區

一、OpenGL頂點數組

作為在立即模式(glBegin()與glEnd()之間)下指定單個頂點資料的替代,你可以儲存頂點資料在一組清單中,包括頂點位置、法線、紋理坐标與顔色資訊。并且你可以通過索引數組繪制標明的幾何圖元。

頂點數組儲存在你的應用程式(系統記憶體),它在用戶端。且處在服務端的OpenGL通路它們。這就是為什麼擁有頂點數組這些特殊指令的原因,使用glEnableClientState()與glDisableClientState()而不是glEnable()與glDisable()。

初始化

OpenGL提供glEnableClientState()與glDisableClientState()函數啟用/禁用6中不同類别的數組。此外,有6個函數用于指定數組的精确位置(位址),是以在你的應用程式中OpenGL可以通路這些數組。

  • glVertexPointer():指定頂點坐标數組指針
  • glNormalPointer():指定法線數組指針
  • glColorPointer():指定RGB顔色數組指針
  • glIndexPointer():指定索引顔色數組指針
  • glTexCoordPointer():指定紋理坐标數組指針
  • glEdgeFlagPointer():指定邊标志數組指針

glDrawArrays()

glDrawArrays()從開啟的數組中順序讀取頂點資料。由于glDrawArray()不準許在頂點數組中跳躍,你必須為每個面重複指定共用頂點。

glDrawElements()

glDrawElements()通過頂點數組相關的随機數組索引繪制圖元序列。

glDrawRangeElements()

與glDrawElements()類似,glDrawRangeElements()也适用于随機通路頂點數組。不過glDrawRangeElements()有額外的2個參數(start與end索引)以指定需要讀取的頂點範圍。

示例:

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(TextVertex), vert);
glTexCoordPointer(2, GL_FLOAT, sizeof(TextVertex), &vert[0][3]);
glDrawArrays(GL_QUADS, 0, index);
// 繪制之後禁用頂點數組
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
           

二、Opengl緩沖區對象VAO

每當我們繪制一個幾何體時,我們需要重複同樣的工作(首先綁定緩沖區、然後設定頂點屬性)。VAO做的事情,它将所有頂點繪制過程中的這些設定和綁定過程集中存儲在一起,當我們需要時,隻需要使用相應的VAO即可。

opengl--頂點數組和緩沖區對象一、OpenGL頂點數組二、Opengl緩沖區對象VAO三、幀緩沖區

綁定并設定VAO

//建立VAO
GLuint VAO;
glGenVertexArrays(1, &VAO);
//設定目前VAO,之後所有操作(注意:這些操作必須是上文VAO中包含的内容所注明的調用,其他非VAO中存儲的内容即使調用了也不會影響VAO)存儲在該VAO中
glBindVertexArray(VAO);
   glBindBuffer(GL_ARRAY_BUFFER, VBO); //設定了VBO
   glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//設定VBO中的資料
   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); //設定頂點屬性(索引為0的屬性,與shader中的内容有互動)
   glEnableVertexAttribArray(0); //設定開啟頂點屬性(索引為0的屬性,與shader中的内容有互動)
glBindVertexArray(0); //解綁VAO(解綁主要是為了不影響後續VAO的設定,有點類似于C++中指針delete後置空,是個好習慣)
           

使用VAO

glUseProgram(shaderProgram);
glBindVertexArray(VAO); //綁定我們需要的VAO,會導緻上面所有VAO儲存的設定自動設定完成
someOpenGLFunctionThatDrawsOurTriangle();   
glBindVertexArray(0);   //解綁VAO
           

三、幀緩沖區

OpenGL 預設把 framebuffer 當作渲染的目的地。它由視窗系統建立并管理。framebuffer Object 是個二維數組的集合,它包括 color buffers, depth buffer, stencil buffer。

與視窗系統提供的幀緩沖區類似,FBO包含一系列渲染目的地的集合;包括顔色,深度和模闆緩沖區。 FBO中的這些邏輯緩沖區稱為可附着的 frame buffer。

有兩種類型的可附着的 framebuffer;紋理(Texture)和renderbuffer。如果紋理被附加到FBO,OpenGL将執行“渲染到紋理”。如果renderbuffer被附加到FBO,則OpenGL會執行“離屏渲染”。

opengl--頂點數組和緩沖區對象一、OpenGL頂點數組二、Opengl緩沖區對象VAO三、幀緩沖區

FBO中,

  • 有多個顔色附加點(GL_COLOR_ATTACHMENT0,…,GL_COLOR_ATTACHMENTn)
  • 一個深度附加點(GL_DEPTH_ATTACHMENT)
  • 一個模闆附加點(GL_STENCIL_ATTACHMENT)。

建立FBO

void glGenFramebuffers(GLsizei n, GLuint* ids)
void glDeleteFramebuffers(GLsizei n, const GLuint* ids)
           

綁定FBO

void glBindFramebuffer(GLenum target, GLuint id)
           

附加Renderbuffer

void glGenRenderbuffers(GLsizei n, GLuint* ids)
void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)
void glRenderbufferStorage(GLenum  target,
                           GLenum  internalFormat,
                           GLsizei width,
                           GLsizei height)
 void glFramebufferRenderbuffer(GLenum target,
                               GLenum attachmentPoint,
                               GLenum renderbufferTarget,
                               GLuint renderbufferId)
           

附加圖像

glFramebufferTexture2D(GLenum target,
                       GLenum attachmentPoint,
                       GLenum textureTarget,
                       GLuint textureId,
                       GLint  level)
           

檢查FBO狀态

FBO完整性規則為:

  • framebuffer可附加圖像的寬度和高度必須不為零。
  • 如果圖像附加到顔色附着點,則圖像必須具有可呈現顔色的内部格式。(GL_RGBA,GL_DEPTH_COMPONENT,GL_LUMINANCE等
  • 如果圖像附加到GL_DEPTH_ATTACHMENT,則圖像必須具有深度可渲染内部格式。(GL_DEPTH_COMPONENT,GL_DEPTH_COMPONENT24等)
  • 如果圖像附加到GL_STENCIL_ATTACHMENT,則圖像必須具有模闆可渲染内部格式。(GL_STENCIL_INDEX,GL_STENCIL_INDEX8等) FBO必須至少安裝一張圖檔。
  • 附加FBO的所有圖像必須具有相同的寬度和高度。 附加顔色附件點的所有圖像必須具有相同的内部格式。
GLenum glCheckFramebufferStatus(GLenum target)
           

示例

...
// create a texture object
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); // automatic mipmap
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, TEXTURE_WIDTH, TEXTURE_HEIGHT, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

// create a renderbuffer object to store depth info
GLuint rboId;
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
                      TEXTURE_WIDTH, TEXTURE_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0);

// create a framebuffer object
GLuint fboId;
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);

// attach the texture to FBO color attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER,        // 1. fbo target: GL_FRAMEBUFFER 
                       GL_COLOR_ATTACHMENT0,  // 2. attachment point
                       GL_TEXTURE_2D,         // 3. tex target: GL_TEXTURE_2D
                       textureId,             // 4. tex ID
                       0);                    // 5. mipmap level: 0(base)

// attach the renderbuffer to depth attachment point
glFramebufferRenderbuffer(GL_FRAMEBUFFER,      // 1. fbo target: GL_FRAMEBUFFER
                          GL_DEPTH_ATTACHMENT, // 2. attachment point
                          GL_RENDERBUFFER,     // 3. rbo target: GL_RENDERBUFFER
                          rboId);              // 4. rbo ID

// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
    fboUsed = false;

// switch back to window-system-provided framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
...
           
..
// set rendering destination to FBO
glBindFramebuffer(GL_FRAMEBUFFER, fboId);

// clear buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// draw a scene to a texture directly
draw();

// unbind FBO
glBindFramebuffer(GL_FRAMEBUFFER, 0);

// trigger mipmaps generation explicitly
// NOTE: If GL_GENERATE_MIPMAP is set to GL_TRUE, then glCopyTexSubImage2D()
// triggers mipmap generation automatically. However, the texture attached
// onto a FBO should generate mipmaps manually via glGenerateMipmap().
glBindTexture(GL_TEXTURE_2D, textureId);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
...
           

繼續閱讀