網(wǎng)站設(shè)計標(biāo)準(zhǔn)字體/競猜世界杯
相關(guān)文章鏈接
C++ OpenGL學(xué)習(xí)筆記(1、Hello World空窗口程序)
目錄
- 繪制橙色三角形繪制
- 1、主要修改內(nèi)容有:
- 1.1、在主程序的基礎(chǔ)上增加如下3個函數(shù)
- 1.2、另外在主程序外面新增3個全局變量
- 1.3、編寫兩個shader程序文件
- 2、initModel()函數(shù)
- 3、initShader函數(shù)
- 3.1、vertexShader.glsl文件
- 3.2、fragmentShader.glsl文件
- 3.3、initShader函數(shù)代碼
- 3、rend函數(shù)
- 綠色隨時間變化的三角形繪制
- 1.1、fragmentShader.glsl文件修改如下
- 1.2、在rend函數(shù)修改如下
- 總代碼
- 1、mainl.cpp
- 2、vertexShader.glsl
- 3、fragmentShader.glsl
三角形是最基礎(chǔ)的一個面圖形,要在一個空的窗口上繪制三角形,就需要在上一節(jié)代碼基礎(chǔ)上進行修改。
繪制橙色三角形繪制
繪制效果
1、主要修改內(nèi)容有:
1.1、在主程序的基礎(chǔ)上增加如下3個函數(shù)
1.2、另外在主程序外面新增3個全局變量
如下
1.3、編寫兩個shader程序文件
vertexShader.glsl文件、fragmentShader.glsl文件
下面一項項的說代碼
2、initModel()函數(shù)
該函數(shù)主要初始化模型,主要是初始化三角形頂點數(shù)據(jù),初始化全局變量VAO、VBO
該函數(shù)內(nèi)部流程大概:
0、初始化頂點數(shù)組,該數(shù)組總共3行,每行都是一個頂點數(shù)據(jù),分別表示該點的x、y、z坐標(biāo)點,所以總共是3個點的數(shù)據(jù)。
1、創(chuàng)建一個VAO
2、綁定VAO,
3、創(chuàng)建一個VBO,
4、綁定VBO,
5、給VBO分配顯存空間,傳輸數(shù)據(jù)
6、告訴shader數(shù)據(jù)解析方式
7、激活錨點
8、給VBO解綁
9、給VAO解綁
該函數(shù)完整代碼如下
void initModel()
{//構(gòu)建模型,在模型數(shù)據(jù)發(fā)送GPU,VAO,VBO 在這里完成的//基礎(chǔ)數(shù)據(jù),三角形頂點float vertices[] = {-0.5f,-0.5f,0.0f,0.5,-0.5,0.0f,0.0f,0.5f,0.0f};glGenVertexArrays(1, &VAO);//創(chuàng)建1個VAOglBindVertexArray(VAO);//綁定VAO//下面初始化VBO,下面的VBO就屬于VAO的管理范圍,以后繪圖直接使用VAO即可glGenBuffers(1, &VBO);//可以同時獲取多個VBO的indexglBindBuffer(GL_ARRAY_BUFFER,VBO);//綁定VBOglBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,GL_STATIC_DRAW);//給GL_ARRAY_BUFFER分配空間,第二個參數(shù):分配多大的空間,第三個參數(shù):從哪里開始讀取數(shù)據(jù),第四個參數(shù):告訴openGL怎么使用這個數(shù)據(jù)//下面做錨定點glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//每個頂點包含3個坐標(biāo),每個坐標(biāo)都是float類型,不進行正則化,步長3 * sizeof(float)glEnableVertexAttribArray(0);//激活0號錨點glBindBuffer(GL_ARRAY_BUFFER, 0);//給VBO解綁glBindVertexArray(0);//給VAO解綁}
3、initShader函數(shù)
該函數(shù)完整形式:void initShader(const char* _vertexPath ,const char* _fragPath );里面兩個參數(shù)分別是兩個shader文件的絕對路徑,那么就先把兩個shader文件擺出來吧
3.1、vertexShader.glsl文件
該文件為頂點數(shù)據(jù)處理文件,主要確定頂點位置。代碼如下
#version 330 core //版本聲明
layout(location = 0) in vec3 aPos;//記得上面在初始化模型里面激活0號錨點的代碼嗎,這是相對應(yīng)的void main()
{//gl_Position 是opengl內(nèi)置全局變量,該變量會在后面進行調(diào)用gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);
};
里面代碼跟普通代碼C++代碼很相似,每行作用都做了注解,先照抄即可;
3.2、fragmentShader.glsl文件
該文件主要是光柵化顯示作用,主要是對頂點數(shù)據(jù)進行內(nèi)插,內(nèi)插后在范圍內(nèi)的進行用指定顏色進行顯示出來。
完整代碼如下:
#version 330 core
out vec4 FragColor;//任何out定義的變量會被輸出到下一步,openGL光柵化的下一步不用管,它是有個管線自動處理的void main()
{FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);//1是白色,0是黑色。橙色RGB為:(1,0.5,0.2)最后一個是alpha通道,默認(rèn)為1};
注意這里出現(xiàn)了out定義的變量,數(shù)據(jù)類型是vec4,在shader語言中還有用in、uniform進行定義變量,數(shù)據(jù)類型可以自定義。區(qū)別是:
in定義的變量是由openGL管線中上一步傳入過來的,上一步的out變量是下一步的in變量,變量名稱不要變化;
uniform定義的變量是由外部C++代碼傳入進來的,后面可以做一個樣例出來,現(xiàn)在先不用管;
管線搞不懂就看下面這張圖:
管線顧名思義就是一根像線的管道,在這個管道中只有幾個步驟可以進行編輯(填充藍(lán)色的),其他步驟不需要程序員去管的(填充灰色的):
3.3、initShader函數(shù)代碼
該代碼看著比較長,里面實際上只干了幾件事情,最終是將shader代碼編譯鏈接在全局變量shaderProgram中。
函數(shù)流程:
1、讀取_vertexPath (vertexShader.glsl)文件到變量_vertexCode中;
2、讀取_fragPath (fragmentShader.glsl)文件到變量 _fragCode中;
3、分別編譯_vertexCode、 _fragCode代碼到_vertexID、_fragID;
4、初始化全局變量shaderProgram,分別將剛剛編譯出來的_vertexID、_fragID鏈接到shaderProgram里面去;
5、分別檢查編譯是否成功、鏈接是否成功,最后進行_vertexID、_fragID的釋放
void initShader(const char* _vertexPath ,const char* _fragPath )
{//shader寫出來,編譯出來std::string _vertexCode("");std::string _fragCode("");std::ifstream _vShaderFile;std::ifstream _fShaderFile;_vShaderFile.exceptions(std::ifstream::failbit| std::ifstream::badbit);_fShaderFile.exceptions(std::ifstream::failbit| std::ifstream::badbit);try {_vShaderFile.open(_vertexPath);_fShaderFile.open(_fragPath);std::stringstream _vShaderStream, _fShaderStream;_vShaderStream << _vShaderFile.rdbuf();_fShaderStream << _fShaderFile.rdbuf();_vertexCode = _vShaderStream.str();_fragCode = _fShaderStream.str();}catch (std::ifstream::failure e) {std::string errStr = "rerad shader fail";std::cout << errStr << std::endl;}const char* _vShaderStr = _vertexCode.c_str();const char* _fShaderStr = _fragCode.c_str();//shader的編譯鏈接unsigned int _vertexID = 0,_fragID = 0;char _infoLog[512];//存儲錯誤信息int _successFlag = 0;//是否成功//編譯_vertexID = glCreateShader(GL_VERTEX_SHADER);//編譯的是VERTEX類型glShaderSource(_vertexID, 1, &_vShaderStr, NULL);//把代碼傳過去glCompileShader(_vertexID);//編譯glGetShaderiv(_vertexID,GL_COMPILE_STATUS,&_successFlag);//獲取編譯情況如何if (!_successFlag) {//如果編譯不成功glGetShaderInfoLog(_vertexID, 512,NULL,_infoLog);std::string errStr(_infoLog);std::cout << errStr << std::endl;}//frag shader _fragID = glCreateShader(GL_FRAGMENT_SHADER);//編譯的是FRAGMENT類型glShaderSource(_fragID, 1, &_fShaderStr, NULL);//把代碼傳過去glCompileShader(_fragID);//編譯glGetShaderiv(_fragID, GL_COMPILE_STATUS, &_successFlag);//獲取編譯情況如何if (!_successFlag) {//如果編譯不成功glGetShaderInfoLog(_fragID, 512, NULL, _infoLog);std::string errStr(_infoLog);std::cout << errStr << std::endl;}//鏈接shaderProgram = glCreateProgram();glAttachShader(shaderProgram,_vertexID);//向program好的加入編譯好的glAttachShader(shaderProgram,_fragID);//向program好的加入glLinkProgram(shaderProgram);//開始鏈接//檢查鏈接是否成功glGetProgramiv(shaderProgram, GL_LINK_STATUS, &_successFlag);if (!_successFlag) {//如果鏈接不成功glGetProgramInfoLog(shaderProgram, 512, NULL, _infoLog);std::string errStr(_infoLog);std::cout << errStr << std::endl;}//釋放glDeleteShader(_vertexID);glDeleteShader(_fragID);}
3、rend函數(shù)
該函數(shù)是繪制函數(shù),是放在while循環(huán)里面的
void rend()
{//渲染函數(shù)//每次循環(huán)都會調(diào)用該函數(shù),直接進行渲染glBindVertexArray(VAO);//使用VAO方式進行繪制glUseProgram(shaderProgram);glDrawArrays(GL_TRIANGLES,0,3);//繪制,從第0個開始畫,起作用的是3個glUseProgram(0);
}
編譯運行的效果
綠色隨時間變化的三角形繪制
該程序是在橙色三角形的基礎(chǔ)上進行變種來的,程序邏輯是從外部傳入一個隨著時間變化的顏色數(shù)據(jù)即可。
主要修改:
1、fragmentShader.glsl文件中,新增一個uniform定義的顏色變量;
2、在rend函數(shù)中新增一個與時間相關(guān)的變換函數(shù),該函數(shù)輸出的值作為綠色波段的顏色值;將新增的綠色波段顏色信息傳入到fragmentShader中即可
1.1、fragmentShader.glsl文件修改如下
//外部傳參的寫法
#version 330 core
out vec4 FragColor;
uniform vec4 MyColor;//通過外部傳參進來
void main()
{FragColor = MyColor;//外部傳進來的顏色直接傳到下一個流程中};
1.2、在rend函數(shù)修改如下
void rend()
{//渲染函數(shù)//外部傳參的寫法,將顏色通過外面?zhèn)魅脒M去===========================================glUseProgram(shaderProgram);//注意這行代碼必須提前,否則黑屏,繪制不出來float _time = glfwGetTime();//獲取時間,通過時間變換來改變渲染顏色;float _green = sin(_time)*0.5f+0.5f;//動態(tài)改變綠色通道的值int _location = glGetUniformLocation(shaderProgram,"MyColor");//獲取MyColor變量位置,MyColor即fragmentShader.glsl文件中用uniform修飾的變量glUniform4f(_location, 0.0f, _green, 0.0f, 1.0f);//把顏色傳入進去( 0.0f, _green, 0.0f, 1.0f)傳入到fragmentShader里面的MyColor變量glBindVertexArray(VAO);//使用VAO方式進行繪制glDrawArrays(GL_TRIANGLES, 0, 3);//繪制,從第0個開始畫,起作用的是3個glUseProgram(0);}
運行后,這窗口中三角形隨著時間的變化不斷循環(huán)顏色發(fā)生變化,如下圖
總代碼
總共代碼在上次環(huán)境配置基礎(chǔ)上,修改3個文件:
1、main.cpp
2、vertexShader.glsl
3、fragmentShader.glsl
1、mainl.cpp
/*
三角形繪制基礎(chǔ)代碼
在這節(jié)課介紹三角形繪制的基礎(chǔ)方法,也會涉及到基礎(chǔ)的shader調(diào)用,其中最關(guān)鍵的概念是
VAO、VBO在OpenGL核心模式下的使用及內(nèi)涵
也會做一個小小的程序結(jié)構(gòu),讓大家方便今后的架構(gòu)慢慢改進先對vertexShader.glsl 進行頂點變換,再傳入fragmentShader.glsl里面插值1、獲取VBO的index
2、綁定VBO的index
3、給VBO分配顯存空間,傳輸數(shù)據(jù)
4、告訴shader數(shù)據(jù)解析方式
5、激活錨點*/
#include <glad/glad.h>
#include "GLFW/glfw3.h"
#include <iostream>#include <string>
#include <fstream>
#include <sstream>unsigned int VBO = 0;
unsigned int VAO = 0;
unsigned int shaderProgram = 0;void rend()
{//渲染函數(shù)每次循環(huán)都會調(diào)用該函數(shù),直接進行渲染//glBindVertexArray(VAO);//使用VAO方式進行繪制//glUseProgram(shaderProgram);//glDrawArrays(GL_TRIANGLES,0,3);//繪制,從第0個開始畫,起作用的是3個//glUseProgram(0);//外部傳參的寫法,將顏色通過外面?zhèn)魅脒M去===========================================glUseProgram(shaderProgram);float _time = glfwGetTime();//獲取時間,通過時間變換來改變渲染顏色;float _green = sin(_time)*0.5f+0.5f;//動態(tài)改變綠色通道的值int _location = glGetUniformLocation(shaderProgram,"MyColor");//獲取MyColor變量位置glUniform4f(_location, 0.0f, _green, 0.0f, 1.0f);//把顏色傳入進去( 0.0f, _green, 0.0f, 1.0f)傳入到fragmentShader里面的MyColor變量glBindVertexArray(VAO);//使用VAO方式進行繪制glDrawArrays(GL_TRIANGLES, 0, 3);//繪制,從第0個開始畫,起作用的是3個glUseProgram(0);}void initModel()
{//構(gòu)建模型,在模型數(shù)據(jù)發(fā)送GPU,VAO,VBO 在這里完成的//基礎(chǔ)數(shù)據(jù),三角形頂點float vertices[] = {-0.5f,-0.5f,0.0f,0.5,-0.5,0.0f,0.0f,0.5f,0.0f};glGenVertexArrays(1, &VAO);//創(chuàng)建1個VAOglBindVertexArray(VAO);//綁定VAO//下面初始化VBO,下面的VBO就屬于VAO的管理范圍,以后繪圖直接使用VAO即可glGenBuffers(1, &VBO);//可以同時獲取多個VBO的indexglBindBuffer(GL_ARRAY_BUFFER,VBO);//綁定VBOglBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,GL_STATIC_DRAW);//給GL_ARRAY_BUFFER分配空間,第二個參數(shù):分配多大的空間,第三個參數(shù):從哪里開始讀取數(shù)據(jù),第四個參數(shù):告訴openGL怎么使用這個數(shù)據(jù)//下面做錨定點glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//每個頂點包含3個坐標(biāo),每個坐標(biāo)都是float類型,不進行正則化,步長3 * sizeof(float)glEnableVertexAttribArray(0);//激活0號錨點glBindBuffer(GL_ARRAY_BUFFER, 0);//給VBO解綁glBindVertexArray(0);//給VAO解綁}void initShader(const char* _vertexPath ,const char* _fragPath )
{//shader寫出來,編譯出來std::string _vertexCode("");std::string _fragCode("");std::ifstream _vShaderFile;std::ifstream _fShaderFile;_vShaderFile.exceptions(std::ifstream::failbit| std::ifstream::badbit);_fShaderFile.exceptions(std::ifstream::failbit| std::ifstream::badbit);try {_vShaderFile.open(_vertexPath);_fShaderFile.open(_fragPath);std::stringstream _vShaderStream, _fShaderStream;_vShaderStream << _vShaderFile.rdbuf();_fShaderStream << _fShaderFile.rdbuf();_vertexCode = _vShaderStream.str();_fragCode = _fShaderStream.str();}catch (std::ifstream::failure e) {std::string errStr = "rerad shader fail";std::cout << errStr << std::endl;}const char* _vShaderStr = _vertexCode.c_str();const char* _fShaderStr = _fragCode.c_str();//shader的編譯鏈接unsigned int _vertexID = 0,_fragID = 0;char _infoLog[512];//存儲錯誤信息int _successFlag = 0;//是否成功//編譯_vertexID = glCreateShader(GL_VERTEX_SHADER);//編譯的是VERTEX類型glShaderSource(_vertexID, 1, &_vShaderStr, NULL);//把代碼傳過去glCompileShader(_vertexID);//編譯glGetShaderiv(_vertexID,GL_COMPILE_STATUS,&_successFlag);//獲取編譯情況如何if (!_successFlag) {//如果編譯不成功glGetShaderInfoLog(_vertexID, 512,NULL,_infoLog);std::string errStr(_infoLog);std::cout << errStr << std::endl;}//frag shader _fragID = glCreateShader(GL_FRAGMENT_SHADER);//編譯的是FRAGMENT類型glShaderSource(_fragID, 1, &_fShaderStr, NULL);//把代碼傳過去glCompileShader(_fragID);//編譯glGetShaderiv(_fragID, GL_COMPILE_STATUS, &_successFlag);//獲取編譯情況如何if (!_successFlag) {//如果編譯不成功glGetShaderInfoLog(_fragID, 512, NULL, _infoLog);std::string errStr(_infoLog);std::cout << errStr << std::endl;}//鏈接shaderProgram = glCreateProgram();glAttachShader(shaderProgram,_vertexID);//向program好的加入編譯好的glAttachShader(shaderProgram,_fragID);//向program好的加入glLinkProgram(shaderProgram);//開始鏈接//檢查鏈接是否成功glGetProgramiv(shaderProgram, GL_LINK_STATUS, &_successFlag);if (!_successFlag) {//如果鏈接不成功glGetProgramInfoLog(shaderProgram, 512, NULL, _infoLog);std::string errStr(_infoLog);std::cout << errStr << std::endl;}//釋放glDeleteShader(_vertexID);glDeleteShader(_fragID);}void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{glViewport(0, 0, width, height);
}void processInput(GLFWwindow *window)
{//檢測是否有外部輸入if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS){glfwSetWindowShouldClose(window, true);//把關(guān)閉狀態(tài)設(shè)置為true}
}int main()
{glfwInit();//初始化上下文環(huán)境glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//要求opengl 3版本以上glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//設(shè)置CORE模式,只能用VAO繪制GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL Core", NULL, NULL);//創(chuàng)建窗體if (window == NULL){std::cout << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);//上下文綁定窗體if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))//初始化函數(shù)指針,為下面函數(shù)做準(zhǔn)備{std::cout << "Failed to initialize GLAD" << std::endl;return -1;}glViewport(0, 0, 800, 600);//設(shè)置需要渲染的視口glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//設(shè)置回調(diào)函數(shù)initModel();//初始化模型initShader("vertexShader.glsl","fragmentShader.glsl");//初始化shader文件while (!glfwWindowShouldClose(window))//創(chuàng)建的window關(guān)掉后就退出while循環(huán){processInput(window);//glClearColor(0.2f, 0.3f, 0.3f, 1.0f);//設(shè)置顏色glClear(GL_COLOR_BUFFER_BIT);//用設(shè)置的顏色把畫布進行清零掉rend();//渲染繪制glfwSwapBuffers(window);glfwPollEvents();}glfwTerminate();std::cout << "Hello World!\n";return 0;
}
2、vertexShader.glsl
#version 330 core
layout(location = 0) in vec3 aPos;
void main()
{//gl_Position 是opengl內(nèi)置全局變量,該變量會在后面進行調(diào)用gl_Position = vec4(aPos.x,aPos.y,aPos.z,1.0);
};
3、fragmentShader.glsl
/*任何out定義的變量會被輸出到下一步*/
//#version 330 core
//out vec4 FragColor;
//void main()
//{
// FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
//
//};//外部傳參的寫法
#version 330 core
out vec4 FragColor;
uniform vec4 MyColor;//通過外部傳參進來
void main()
{FragColor = MyColor;//外部傳進來的顏色直接傳到下一個流程中};