前往
大廳
主題

【OpenGL學習筆記】今天,猴子會將他的三角形上色ㄌ

%%鼠 拒收病婿 | 2021-04-15 22:41:30 | 巴幣 1028 | 人氣 687

前言:
程式碼可以直接去Notion貼。
跟著這影片打ㄉ,只是做其他延伸。

成品:

先從Main看


60-75行,來自glfw範例文件,創個全黑的640*480視窗。

77行 glewInit() :
glew是OpenGL Extension Wrangler Library,提供方便開發的程式庫。
他文件有講
《First you need to create a valid OpenGL rendering context and call glewInit() to initialize the extension entry points. If glewInit() returns GLEW_OK, the initialization succeeded and you can use the available extensions as well as core OpenGL functionality. For example:》
意思是要先有"視窗"可以render才能glewInit()。 所以才需放在生成視窗的程式碼下方。

82-86行: 定義3個2維座標。 怎麼知道是2維的下面會說。

88行 unsigned int buffer;  //創個變數等等去裝buffer的id
unsigned int是不為負數的整數宣告,同opengl自己創的型態"GLuint"。影片中有講到建議使用c++原本的型態而非openGL的,原因是不想被綁定在opengl。

89行 glGenBuffers(1, &buffer);  // 產生指定數量的buffer names
glGenBuffers(buffer 數量, &id)

"&id"官方文件說是 《an array in which the generated buffer object names are stored.》說是array,應該是array開始的位置。

如果調皮這樣玩:
輸出:  b1 1 b2 4
無法保證id是連續的int,但能保證回傳的id目前沒被使用。

90行: glBindBuffer(GL_ARRAY_BUFFER, buffer); //(usage , id)
glBindBuffer(target, buffer)
設定該buffer的儲存處理方式(?。
target: 決定bind的處理型態。 ()

Buffer Binding Target Purpose
GL_ARRAY_BUFFER Vertex attributes
GL_ATOMIC_COUNTER_BUFFER Atomic counter storage
GL_COPY_READ_BUFFER Buffer copy source
GL_COPY_WRITE_BUFFER Buffer copy destination
GL_DISPATCH_INDIRECT_BUFFER Indirect compute dispatch commands
GL_DRAW_INDIRECT_BUFFER Indirect command arguments
GL_ELEMENT_ARRAY_BUFFER Vertex array indices
GL_PIXEL_PACK_BUFFER Pixel read target
GL_PIXEL_UNPACK_BUFFER Texture data source
GL_QUERY_BUFFER Query result buffer
GL_SHADER_STORAGE_BUFFER Read-write storage for shaders
GL_TEXTURE_BUFFER Texture data buffer
GL_TRANSFORM_FEEDBACK_BUFFER Transform feedback buffer
GL_UNIFORM_BUFFER Uniform block storage


91行 glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), position, GL_STATIC_DRAW);
creates and initializes a buffer object's data store。

void glBufferData(
GLenum target, //哪種型態的容器駐列
GLsizeiptr size, //資料大小
const GLvoid * data,   //資料
GLenum usage);
size這裡直接hardcode 6 * sizeof(float)。
usage is a hint to the GL implementation as to how a buffer object's data store will be accessed.(告訴GL該資料是如何被訪問的。)
依訪問頻率分:
  • STREAM : 資料只寫入一次,並訪問次數少。
  • STATIC : 資料只寫入一次,並訪問次數多。
  • DYNAMIC : 資料寫入次數多,訪問次數多。
依訪問性質分(參考):
  • DRAW : app寫入但不讀取。 you will put data into the buffer, but you will not read from it
  • READ: 讀取但不寫入。 you will read data from the buffer, but you will not write to it (typically for transform feedback or pixel buffers)
  • COPY:對buffer資料不直接讀寫,由GL讀寫。you will neither read from nor write to the buffer directly.
93行: glEnableVertexAttribArray(0);
index=0,意思是從頭開始讀取vertex。在這裡就是position[0]

94行: glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
void glVertexAttribPointer(
GLuint index,
GLint size,  //維度,僅1~4,2=2D
GLenum type, //data type
GLboolean normalized, //是否需要做normalized處理
GLsizei stride, //vertex與vertex之間的byte數量
const GLvoid * pointer);

注意stride是指vertex資料之間的byte數量。 這裡vertex資料只有單純的xy兩個float,所以是sizeof(float) * 2。
假設一個點有
{
float x
float y
float uv_x
float uv_y
}
則stride= sizeof(float) * 4
但一個 vertex資料型態通常會有position、normal、uv、textcord....等資訊,可以將該資訊包成一個資料型態Vertex,則stride=sizeof(Vertex)*n

96-120行: hardcode vs和fs程式碼。
99、112行算是變數宣告,layout(location=0)是屬性索引(attribute index),例如
layout(location = 2) in vec3 values[4];
會將values四個陣列空間放置在索引2,3,4,5。
更多詳細的可以看Layout Qualifier (GLSL),擷取段有趣的地方:
似乎搞懂了Unity shader的vs和fs變數宣告道理了

121行: 自訂函數如下

寫(const string& vertexShader, const string& fragmentShader) 或(string vertexShader, string fragmentShader)都可以動,&符號作為引用聲明用,意即給變數取別名,但使用的是同一個位址,後者寫法是直接將值copy一份進入函數。

43、44是自訂函數:

第8行: unsigned int id = glCreateShader(type); 產生並回傳一個空的shader object。傳入的type可以有:GL_COMPUTE_SHADER ,GL_VERTEX_SHADER , GL_TESS_CONTROL_SHADER ,GL_TESS_EVALUATION_SHADER , GL_GEOMETRY_SHADER ,GL_FRAGMENT_SHADER。

第9行: 把string轉成char陣列

第10行: glShaderSource(id, 1, &src, nullptr);
Replaces the source code in a shader object。設定shader的原始碼。
void glShaderSource(
GLuint shader,  //shader 物件
GLsizei count, //原始碼數量
const GLchar **string, //原始碼
const GLint *length);  //原始碼(string)長度,null的話會用讀到完

第11行: glCompileShader(id);
就....CompileShader  編譯成功回傳GL_TRUE(=1) 反之GL_FALSE (=0) ,可以用GL_COMPILE_STATUS檢查。

第15-36行: 用glGetShaderiv(id, GL_COMPILE_STATUS, &result); 抓取GL_COMPILE_STATUS狀態,若FALSE則送出error資訊並刪除shader。


第44、45行: 傳入Shader_type取得shader id。
如果cout vs和fs會得到2和3。

備註:A program Object represents fully processed executable code。

實驗: cout第122回傳的shader值為1

第131:glDrawArrays(GL_TRIANGLES, 0, 3);
void glDrawArrays( GLenum mode, //繪製的種類
GLint first,   //first index
GLsizei count);  //數量
這裡是剛好是畫3個點。







送禮物贊助創作者 !
0
留言

創作回應

朱朱
作者,讚喔,unity的吧,看到有shader tag,加油喔
2021-04-25 02:35:55
%%鼠 拒收病婿
這篇的不是哦! 是純C++和OpenGL
2021-04-25 13:42:32
Shark
unsigned int buffer;
glGenBuffers(3, &buffer);
這樣寫是會出問題的,glGenBuffers()第一參數填3代表要叫它產生3個buffer識別碼,第二參數必須有儲存3個int的空間,但「unsigned int buffer;」只有一個int的空間,傳回另外兩個int時會修改到其他變數(無法預料會改到什麼,看此時記憶體裡有什麼東西)。

這樣寫才對
unsigned int buffer[3];
glGenBuffers(3, buffer);
此時buffer[0]、buffer[1]、buffer[2]是三個可用的buffer識別碼,可以分別對它們操作。
2021-05-14 18:25:28
%%鼠 拒收病婿
感謝! 當初學的時候也很懷疑為什麼只用一個int,想說&是傳址呼叫,應該會接續開頭位置存,原來會有複寫原本位置資料的問題[e15]
2021-05-15 12:37:14
追蹤 創作集

作者相關創作

更多創作