1. 程式人生 > >New程式媛OpenGL全解析之—第一個OpenGL程式解析

New程式媛OpenGL全解析之—第一個OpenGL程式解析

大家好!

本期丹丹將給大家解析第一個OpenGL程式


本期視訊的連結地址是:

https://www.bilibili.com/video/av21319715

大家也可以直接在bi站首頁搜尋:New程式媛 ,即可看到相應視訊

本期的資源和程式碼下載連結是:

連結:https://pan.baidu.com/s/1w4PiW8gNwiIu9gIOxUW_VA 密碼:mpfz

視訊和文章一起搭配效果更好哦~

首先咱們來看看今天程式碼的完整版:





程式碼執行起來的效果如下圖:

接下來的工作就是逐句來做解析啦!

第一個模組我們要來看的就是main 函式,因為main函式是我們的程式入口函式。


glutInit:該函式的呼叫是,glut提供的負責初始化的函式,它必須是應用程式呼叫的第一個glut函式。

glutInitDisplayMode:設定了程式所使用的視窗型別,GLUT_DOUBIE表示使用了雙緩衝,GLUT_RGBA表示設定視窗使用RGBA顏色。

glutInitWindowSize:設定視窗的大小。

glutCreateWindow:建立視窗,如果當前的系統環境可以滿足glutDisplayMode的顯示模式要求。

glewInit: glew庫的初始化

glutDisplayFunc:它設定了顯示會調函式,即glut在每次更新視窗內容的時候會自動執行的函式。

Init:自定義的一個初始化函式。

glutMainLoop:這是一個無限之行的迴圈,他會負責一直處理視窗和作業系統的使用者輸入等操作,比如它會判斷視窗是否需要進行重繪,如果需要它就會自動呼叫glutDisplayFunc註冊的函式。

接下來看看繪製的頂點資料初始化:


vertices陣列:頂點資料的定義,我們一共定義了四個頂點,每個頂點有xyz 三個分量

indices陣列 :索引資料的定義,索引號是從0開始,索引0表示的是載入到程式中頂點資料中的第一個頂點,而陣列0 1 3則表示繪製順序是分別取到0號1號3號頂點依次繪製

VAO: 表示vertex array object  的ID

VBO: 表示vertex buffer object 的ID

EBO: 表示elements buffer object的ID

知識點:

很多 OpenGL命令都是 glGen*的形式,它們負責分配不同型別的 OpenGL

物件的名稱。這裡的名稱就是類似C語言中的一個指標變數,我們必須分配記憶體並且用名稱引用它之後,名稱才有意義。在 OpenGL中,這個分配的機制叫做繫結物件( bind an object),

它是通過一系列 glBind*形式的函式集合去實現的。如果繫結到一個已經建立的頂點陣列物件中,那麼會啟用這個頂點陣列物件,並且直接影響物件中所儲存的頂點陣列狀態。

有了這些知識點,我們就來一起看看InitData函式:

glGenVertexArrays(1, &VAO); 分配一個頂點陣列物件,ID儲存在VAO

glGenBuffers(1, &VBO);分配一個頂點快取物件,ID儲存在VBO

glGenBuffers(1, &EBO);分配一個索引快取物件,ID儲存在EBO

glBindBuffer(GL_ARRAY_BUFFER, VBO);綁定了一個頂點陣列物件。

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);指定上句繫結buffer物件的具體資料

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);綁定了一個索引陣列物件。

glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);指定上句繫結buffer物件的具體資料

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);該函式的呼叫是告訴OpenGL從記憶體中如何取資料。

接下來的三條語句就是將資料內容解綁,也就是重置為零ID,即為不繫結和操作任何資料。

glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, 0); 

glBindVertexArray(0); 

有了資料,我們要來看的就是對應的著色器程式碼啦。

知識點:

對於每一個 OPENGL程式,當它所使用的 OPENGL版本高於或等於3.1時,都需要指定至少兩個著色器:頂點著色器和片元著色器。

對於 OPENGL程式設計師而言,著色器就是使用 OPENGL著色語言( OPENGL Shading Language,GLSL)編寫的一個小型函式。GLSL是構成所有 OPENGL著色器的語言,它與C++語言非常類似,儘管GLSL中的所有特性並不能用於 OPENGL的每個著色階段。我們可以以字串的形式傳輸GLSL著色器到 OPENGL。今天我們的例子中也正是這樣使用的。著色器的詳細內容我們會在接下來的推送中給大家詳細講解。

首先看到我們的vertexShaderSource(頂點著色器)和fragmentShaderSource(片元著色器)定義:


#version 330core  指定了我們所用的 Opengl著色語言的版本。330表示430版本。可能大家會疑惑,我們不是講4.3版本麼?沒關係,此處改成430即可。

layout(location=0),是佈局限定,目的是為變數提供元資料。我們可以使用佈局限定符來設定很多不同的屬性,其中有些是與不同的著色階段相關的。

在這裡,設定 position的位置屬性 location為0。

in欄位,它指定了資料進入著色器的流向,還可以宣告變數為out。片元著色器中我們就使用的是out,表示輸出資料。

position和color都是我們自己宣告的變數名,顧名思義就是位置和顏色。

而gl_Positon則是頂點著色器的指定輸出位置。

我們在著色器的main()函式中實現它的主體部分。 Opengl的所有著色器,無論是

處於哪個著色階段,都會有一個main()函式。對於頂點著色器而言,它所實現的就是將輸入的頂點位置複製到頂點著色器的指定輸出位置gl_Position中。而片元著色器的作用則是將輸出的顏色設定為指定的顏色,顏色分量的四個值分別是RGBA。

知識點:

Opengl著色器程式的編寫與C語言等基於編譯器的語言非常類似。我們使用編譯器來解析程式,檢查是否存在錯誤,然後將它翻譯為目的碼。然後,在連結過程中將一系列目標檔案合併,併產生最終的可執行程式。在程式中使用GLSL著色器的過程與之類似,只不過編譯器和連結器都是 OPENGL API的一部分而已。

程式中通過下面的步驟我們對每個著色器程式進行設定。

對於每個著色器物件:

1)建立一個著色器物件。

2)將著色器原始碼編譯為物件。

3)驗證著色器的編譯是否成功。

然後需要將多個著色器物件連結為一個著色器程式,包括:

1)建立一個著色器程式。
2)將著色器物件關聯到著色器程式。
3)連結著色器程式。
4)判斷著色器的連結過程是否成功完成。
5)使用著色器來處理頂點和片元。

好了,那咱們再來看看著色器程式碼部分:


glCreateShader:根據給定的引數建立著色器物件。

glShaderSource:指定著色器物件的原始碼內容。

glCompileShader:編譯。

glGetShaderiv:根據我們給定的引數,判斷編譯是否成功。

glCreateProgram:建立一個著色器程式。

glAttachShader:將著色器物件關聯到著色器程式。

glLinkProgram:連結著色器程式。

glGetProgramiv:判斷著色器的連結過程是否成功完成。

glDeleteShader:刪除釋放指定的著色器物件。

好啦,資料初始化完成,著色器也初始化完成啦


接著就是咱們的Init函式進行統一呼叫了

glClearColor:指定了背景色

RenderScene函式逐句解析:

glClear:指定每次渲染清空掉的是顏色緩衝區的內容。

glUseProgram:使用指定的著色器程式。

glBindVertexArray:繫結對應的頂點陣列,引數為0是解綁。

glDrawElements:按照指定圖元和指定索引陣列繪製對應的圖形。

glutSwapBuffers:從後臺緩衝區重新整理到前臺緩衝區。

好啦~咱們的第一個程式就解析工作完畢!碼起來~~~~

希望小夥伴們多多捧場,新增關注並介紹給身邊的小夥伴哦丹丹也期待大家的意見和建議,歡迎小夥伴們積極留言