LearnGL - 學習筆記目錄
本人才疏學淺,如有什麼錯誤,望不吝指出。
上一篇:LearnGL - 05.2 - Texture - 實現類似2D UI流光動畫。
這一篇:到這篇,我終於忍不了了,太多重複代碼了。所以我們將一些可複用代碼整理一下,一些通用型比較強的功能都統統封裝一下。
這次先提取 Main 中的重複代碼。
後面再提煉:GameObject、Mesh、Camera、Material、等。
以方便後續增加 OpenGL 學習項目的便利性。
但前提先增加對 OpenGL 設計規範的熟悉程度。
my_init.h
初始化相關的內容:
- 創建窗體
- 創建 OpenGL Context
- 提供外部設置回調初始化
- 提供外部設置更新/繪製回調
- 提供外部設置退出程序前回調
- 提供執行入口:run()
my_gl_check_error.h
對 GL 的錯誤狀態的檢測
my_simple_load_tex.h
簡單加載紋理
外部使用
// jave.lin
#include<glad/glad.h>
//#include"linmath.h"
// 把linmath.h 放在 iostream 之前include會有錯誤,所以放到iostream 後include就好了
// 而這個錯誤正式 xkeycheck.h 文件內 #error 提示的,所以可以使用 #define _XKEYCHECK_H 這個頭文件的引用標記宏
// 就可以避免對 xkeycheck.h 頭文件的 include 了。
#include<iostream>
#include<linmath.h>
#include<shader.h>
// 使用 stb_image.h 的加載庫
// github 源碼:https://github.com/nothings/stb/blob/master/stb_image.h
#define STB_IMAGE_IMPLEMENTATION
#include<stb_image.h>
// 將之前的打印版本信息代碼包含一下
#include<my_init.h>
#include<my_gl_check_error.h>
#include<my_simple_load_tex.h>
using namespace my_util;
GLfloat vertices[] = {
// x, y, z
// 直接放4個頂點
-0.5f, -0.5f, 0.0f, // 第0個頂點,左下角
0.5f, -0.5f, 0.0f, // 第1個頂點,右下角
0.5f, 0.5f, 0.0f, // 第2個頂點,右上角
-0.5f, 0.5f, 0.0f, // 第3個頂點,左上角
};
GLfloat uvs[] = { // 頂點的 uv 座標
0.0f, 0.0f, // 左下角
1.0f, 0.0f, // 右下角
1.0f, 1.0f, // 右上角
0.0f, 1.0f, // 左上角
};
GLuint indices[] = { // 注意索引從0開始!通過索引緩存來指定 圖元 組成 用的 頂點有哪些
0, 1, 3, // 放置頂點的索引,第一個三角形
1, 2, 3 // 放置頂點的索引,第二個三角形
};
GLint vpos_location, vuv_location;
GLuint vertex_buffer[2], index_buffer;
GLuint vertex_array_object;
GLuint texture[3];
GLuint pixelBufObject;
GLint success, infoLogLen;
ShaderProgram* shaderProgram;
GLuint win_width, win_height;
void _stdcall OnBeforeInitWinCallback(InitInfo* info) {
info->width = win_width = 600;
info->height = win_height = 600;
info->print_version_info = true;
const char* title = "05_03_ExtracMain_GLFW_SrcCode";
strcpy_s(info->win_title, strlen(title) + 1, title);
}
void _stdcall OnInitCallback() {
// 打印支持最大的頂點支持的數量
int nrAttributes;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &nrAttributes);
std::cout << "Maximum number of vertex attributes supported : " << nrAttributes << std::endl;
// 打印着色器支持最大的紋理圖像單元的數量
int maxTexUnit;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTexUnit);
std::cout << "Maximun number of texture image units : " << maxTexUnit << std::endl;
// 打印着色器支持最大的所有組合的紋理圖像單元的數量
int maxCombinedTexUnit;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxCombinedTexUnit);
std::cout << "Maximun number of Combined texture image units : " << maxCombinedTexUnit << std::endl;
// 用 lambda 設置,獲取 pic 目錄的回調,後面在封裝
g_GetPicturePathCallback = [](char* receiveBuff, const char* file)->char* {
char buf[MAX_PATH];
sprintf_s(buf, "..\\..\\Dependencies\\Pic\\%s", file);
strcpy_s(receiveBuff, MAX_PATH, buf);
return receiveBuff;
};
// 用 lambda 設置,獲取 shader 目錄的回調,後面在封裝
g_GetShaderPathCallback = [](char* receiveBuff, const char* file)->char* {
char buf[MAX_PATH];
sprintf_s(buf, "..\\..\\Dependencies\\Shaders\\%s", file);
strcpy_s(receiveBuff, MAX_PATH, buf);
return receiveBuff;
};
shaderProgram = new ShaderProgram;
// shader program init 5 - 根據shader源碼的相對路徑(變量),加載deps下的shader
char vs_path[MAX_PATH], fs_path[MAX_PATH];
g_GetShaderPathCallback(vs_path, "TestingTexture\\tex_2d_ui_flash_light.vert");
g_GetShaderPathCallback(fs_path, "TestingTexture\\tex_2d_ui_flash_light.frag");
if (!shaderProgram->initByPath(vs_path, fs_path)) {
std::cout << "ShaderProgram init Error: " << shaderProgram->errorLog() << std::endl; // 輸出shader program錯誤
exit(EXIT_FAILURE);
}
glCreateTextures(GL_TEXTURE_2D, 3, texture); // 創建 3 個紋理對象
glActiveTexture(GL_TEXTURE0); // 激活第 0 索引紋理單元
glBindTextureUnit(0, texture[0]); // 紋理單元 0 綁定:主紋理
glActiveTexture(GL_TEXTURE1); // 激活第 1 索引紋理單元
glBindTextureUnit(1, texture[1]); // 紋理單元 0 綁定:遮罩紋理
glActiveTexture(GL_TEXTURE2); // 激活第 2 索引紋理單元
glBindTextureUnit(2, texture[2]); // 紋理單元 0 綁定:閃光/流光紋理
checkGLError();
loadTexture(texture[0], "my_tex.png"); // 加載紋理對象0:主紋理
loadTexture(texture[1], "my_tex_flash_mask.jpg"); // 加載紋理對象1:遮罩紋理
loadTexture(texture[2], "flash.png"); // 加載紋理對象2:閃光/流光紋理
checkGLError();
vpos_location = shaderProgram->getAttributeLoc("vPos"); // 獲取 頂點着色器中的頂點 attribute 屬性的 location
vuv_location = shaderProgram->getAttributeLoc("vUV"); // 獲取 頂點着色器中的頂點 attribute 屬性的 location
glGenVertexArrays(1, &vertex_array_object); // 生成1個 VAO
glGenBuffers(2, vertex_buffer); // 創建2個 VBO,這裏我們因爲有一個一樣的頂點座標,一個一樣的頂點UV
glGenBuffers(1, &index_buffer); // 創建1個 EBO,因爲兩個 Quad 的頂點索引順序都是一樣的
//
// === VAO[0] ===
//
glBindVertexArray(vertex_array_object); // 綁定 VAO[0],那麼之後的 vbo, ebo,的綁定指針都是指向該 VAO 中的,還有頂點格式(規範)都會保存在該 VAO
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[0]); // 綁定 VBO[0]
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 設置 VBO 座標數據
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[1]); // 綁定 VBO[1]
glBufferData(GL_ARRAY_BUFFER, sizeof(uvs), uvs, GL_STATIC_DRAW); // 設置 VBO uv數據
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); // 綁定 EBO
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 設置 EBO 數據
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[0]); // 綁定 VBO[0],因爲後面要設置該 VBO 的座標格式
glVertexAttribPointer(vpos_location, 3, GL_FLOAT, GL_FALSE, // 設置 頂點屬性 vPos 格式
sizeof(GLfloat) * 3, (GLvoid*)0);
glEnableVertexAttribArray(vpos_location); // 啓用 頂點緩存 location 位置的屬性
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer[1]); // 綁定 VBO[1],因爲後面要設置該 VBO 的uv格式
glVertexAttribPointer(vuv_location, 2, GL_FLOAT, GL_FALSE, // 設置 頂點屬性 vUV 格式
sizeof(GLfloat) * 2, (GLvoid*)0);
glEnableVertexAttribArray(vuv_location); // 啓用 頂點緩存 location uv的屬性
glViewport(0, 0, win_width, win_height); // 設置視口座標
}
void _stdcall OnBackBuffResizeCallback(const int width, const int height) {
glViewport(0, 0, width, height);
win_width = width;
win_height = height;
}
void _stdcall OnUpdateCallback() {
glClearColor(0.1f, 0.2f, 0.1f, 0.f); // 設置清理顏色緩存時,填充顏色值
glClear(GL_COLOR_BUFFER_BIT); // 清理顏色緩存
shaderProgram->use(); // 使用此着色器程序
shaderProgram->setInt("main_tex", 0); // 主 紋理設置採樣器採樣 0 索引紋理單元
shaderProgram->setInt("mask_tex", 1); // 遮罩 紋理設置採樣器採樣 1 索引紋理單元
shaderProgram->setInt("flash_light_tex", 2); // 閃光/流光 紋理設置採樣器採樣 2 索引紋理單元
shaderProgram->setFloat("time", (float)glfwGetTime()); // 測試用就直接用字符串了,方便一些
glBindVertexArray(vertex_array_object); // 先繪製 VAO[0] 的 VBO,EBO,VAF,ENABLED
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (GLvoid*)0); // 參數1:繪製三角圖元;參數2:取6個索引來繪製三角圖元(每個三角圖元需要3個,所以可以畫兩個三角圖元);參數3:將 GL_ELEMENT_ARRAY_BUFFER 每個元素視爲 uint 類型;參數4:設置索引緩存的字節偏移量。也可以設置爲另一個 緩存數據的指針,即:使用另一個數據。
}
void _stdcall OnBeforeExitCallback() {
glDeleteBuffers(1, &pixelBufObject); // 測試刪除 BO
glDeleteBuffers(2, vertex_buffer); // 測試刪除 VBO
glDeleteBuffers(1, &index_buffer); // 測試刪除 EBO
glDeleteBuffers(1, &vertex_array_object); // 測試刪除 VAO
glDeleteTextures(3, texture); // 刪除紋理對象 TO
delete shaderProgram; // 銷燬 shader program
checkGLError(); // 最後再看看GL還有什麼錯誤
}
int main() {
g_BeforeInitWinCallback = OnBeforeInitWinCallback;
g_InitCallback = OnInitCallback;
g_BackBuffResizeCallback = OnBackBuffResizeCallback;
g_UpdateCallback = OnUpdateCallback;
g_BeforeExitCallback = OnBeforeExitCallback;
return run();
} // int main() {