既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
//我们将一个Alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
//编译
//编译片段着色器的过程与顶点着色器类似,只不过我们使用GL_FRAGMENT_SHADER常量作为着色器类型:
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
**着色器程序**:多个着色器合并之后并最终链接完成的版本
如果要使用刚才编译的着色器我们必须把它们链接(Link)为一个着色器程序对象,然后在渲染对象的时候激活这个着色器程序。**已激活着色器程序的着色器将在我们发送渲染调用的时候被使用。**
注意:当链接着色器至一个程序的时候,它会把每个着色器的输出链接到下个着色器的输入。当输出和输入不匹配的时候,你会得到一个连接错误。
//创建一个程序对象很简单:glCreateProgram函数创建一个程序,并返回新创建程序对象的ID引用。
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
//现在我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
glAttachShader(shaderProgram, vertexShader);//把着色器附加到了程序上
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);//然后用glLinkProgram链接。
//得到的结果就是一个程序对象,我们可以调用glUseProgram函数,
//用刚创建的程序对象作为它的参数,以激活这个程序对象:
glUseProgram(shaderProgram);//调用之后每个着色器调用和渲染调用都会使用这个程序对象
//在把着色器对象链接到程序对象以后,记得删除着色器对象,我们不再需要它们了
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
我们已经把输入顶点数据发送给了GPU,并指示了GPU如何在顶点和片段着色器中处理它。就快要完成了,但还没结束,OpenGL还不知道它该如何解释内存中的顶点数据,以及它该如何将顶点数据链接到顶点着色器的属性上。
![在这里插入图片描述](https://img-blog.csdnimg.cn/96ad3f0c887f4db49fc0bc857fa6e8c4.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
## 3、实践
## 3.1、三角形
![在这里插入图片描述](https://img-blog.csdnimg.cn/80b0a6782ae442c299eb357cbe5eefba.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
#include
#include <glad/glad.h>
#include <GLFW/glfw3.h>
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
/*
顶点着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
使用in关键字,在顶点着色器中声明所有的输入顶点属性
layout (location = 0)设定了输入变量(顶点属性)的位置值;并且后面链接顶点属性设置的时候会通过顶点属性位置值进行绑定
vec3 表示三个分量的值(注意每个值都是浮点数类型)
第二行就是表示在位置0的地方有一个三个分量的输入变量aPos
将输入的三维aPos转换为四维并赋值给全局变量gl_Position
/
const char vertexShaderSource = “#version 330 core\n”
“layout (location = 0) in vec3 aPos;\n”
“void main()\n”
“{\n”
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
“}\0”;
/*
片段着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
out 表示输出变量 四维向量的变量FragColor
暂时自定义为 一个Alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。
RGBA的四分量向量
片段着色器所做的是计算像素最后的颜色输出。为了让事情更简单暂时自定义为 我们的片段着色器将会一直输出橘黄色。
/
const char fragmentShaderSource = “#version 330 core\n”
“out vec4 FragColor;\n”
“void main()\n”
“{\n”
" FragColor = vec4(1.0f, 0.2f, 0.2f, 1.0f);\n"
“}\n\0”;
int main()
{
/1、 初始化opengl窗口***************/
//glfw 初始化和配置
glfwInit();//初始化GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//子版本号
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//指定哪个配置文件配置上下文:GLFW我们使用的是核心模式
#ifdef APPLE//如果时mac os xp等系统则要进行配置一下才能生效
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//glfw创建窗口
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//GLFW将我们窗口的上下文设置为当前线程的主上下文
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//GLAD加载所有的opengl函数指针
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
/******************************2、 着色器编译编译链接 *********************************************/
//编写 编译顶点着色器
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);//传入GL_VERTEX_SHADER表示创建顶点着色器
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(vertexShader);//编译
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
cout << "ERROR:Shader::Vertex::Compilation Fail\n" << infoLog << endl;
}
//编写 编译片段着色器
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);//传入GL_FRAGMENT_SHADER 表示创建片段着色器
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(fragmentShader);//编译
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glad_glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
cout << "ERROR:Shader::fragment::Compilation Fail:" << infoLog << endl;
}
//链接着色器程序
unsigned int shaderProgram = glCreateProgram(); //创建着色器程序
glAttachShader(shaderProgram, vertexShader);//之前编译的着色器附加到程序对象上
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);//链接它们
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);//检查程序是否链接报错
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
cout << "ERROR:Program::shaderProgram::Link Fail:" << infoLog << endl;
}
glDeleteShader(vertexShader);//着色器程序已链接完毕则不再需要可以进行delete了
glDeleteShader(fragmentShader);
/******************************3、 顶点属性缓存这些 *********************************************/
//设置顶点数据 和顶点缓存对象 以及配置顶点属性
//标准化设备坐标 三角形的三个顶点
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);//创建一个顶点数组 与顶点属性相绑定
glGenBuffers(1, &VBO);//创建顶点缓冲对象
glBindVertexArray(VAO);//绑定顶点数组
glBindBuffer(GL_ARRAY_BUFFER, VBO);//将GL_ARRAY_BUFFER类型的缓存与VBO绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//之前定义的顶点数据复制到缓冲的内存
/*
0;指定我们要配置的顶点属性 就是顶点着色器里面location那个
*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);
glEnableVertexAttribArray(0);//以顶点属性位置值0作为参数,启用顶点属性
glBindBuffer(GL_ARRAY_BUFFER, 0);//VBO 已经与顶点属性数组VAO进行绑定了 那么GL_ARRAY_BUFFER就可以解除绑定
glBindVertexArray(0);//您可以在之后解除绑定VAO,这样其他VAO调用就不会意外地修改这个VAO
//渲染循环
//程序在我们主动关闭它之前不断绘制图像并能够接受用户输入 GLFW退出前一直保持运行
while (!glfwWindowShouldClose(window))//检查一次GLFW是否被要求退出
{
//可接收键盘输入esc从而退出
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //设置状态函数
glClear(GL_COLOR_BUFFER_BIT);//使用状态函数
glUseProgram(shaderProgram);//使用着色器程序
glBindVertexArray(VAO);//绑定顶点数组 就是使用顶点属性
/*
我们希望绘制的是一个三角形,这里传递GL_TRIANGLES给它。
第二个参数指定了顶点数组的起始索引,我们这里填0。
最后一个参数指定我们打算绘制多少个顶点,这里是3
(我们只从我们的数据中渲染一个三角形,它只有3个顶点长)
*/
glDrawArrays(GL_TRIANGLES, 0, 3);//它使用当前激活的着色器,之前定义的顶点属性配置,和VBO的顶点数据(通过VAO间接绑定)来绘制图元。
// glBindVertexArray(0); 按道理我们需要每次都解绑定,但是本程序只有一个则可以不用了
glfwSwapBuffers(window);//交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
glfwPollEvents();//检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
//释放/删除之前的分配的所有资源
glfwTerminate();
return 0;
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//会返回这个按键是否正在被按下
glfwSetWindowShouldClose(window, true);//把WindowShouldClose属性设置为 true的方法关闭GLFW
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
//左上角坐标xy和宽高
glViewport(0, 0, width, height);//OpenGL的显示试图
}
## 3.2、四边形
**索引缓冲对象EBO**:
背景:绘制矩形的时候如果不断绘制三角形那么就有顶点重复问题;如果我们可以只储存不同的顶点,并设定绘制这些顶点的顺序。这样子我们只要储存4个顶点就能绘制矩形了,之后只要指定绘制的顺序就行了。
工作方式:索引缓冲对象的工作方式正是这样的。和顶点缓冲对象一样,EBO也是一个缓冲,它专门储存索引,OpenGL调用这些顶点的索引来决定该绘制哪个顶点。
//顶点
float vertices[] = {
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
//索引
unsigned int indices[] = { // 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
unsigned int EBO;
glGenBuffers(1, &EBO);//定义索引缓冲对象
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//GL_ELEMENT_ARRAY_BUFFER类型绑定到EBO
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//glBufferData把索引复制到缓冲里
//用glDrawElements来替换glDrawArrays函数,来指明我们从索引缓冲渲染。
//使用glDrawElements时,我们会使用当前绑定的索引缓冲对象中的索引进行绘制:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
/*
第一个参数:我们绘制的模式。
第二个参数:我们打算绘制顶点的个数
第三个参数:索引的类型,这里是GL_UNSIGNED_INT
第四个参数:我们可以指定EBO中的偏移量(或者传递一个索引数组,但是这是当你不在使用索引缓冲对象的时候),但是我们会在这里填写0。
*/
注意:顶点数组对象同样可以保存索引缓冲对象的绑定状态。VAO绑定时正在绑定的索引缓冲对象会被保存为VAO的元素缓冲对象。绑定VAO的同时也会自动绑定EBO。但是当目标是GL\_ELEMENT\_ARRAY\_BUFFER的时候,VAO会储存glBindBuffer的函数调用。这也意味着它也会储存解绑调用,所以确保你没有在解绑VAO之前解绑索引数组缓冲,否则它就没有这个EBO配置了。
![在这里插入图片描述](https://img-blog.csdnimg.cn/4ba32a30a3334ab4a1274c889ccc3ef2.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/1c99f99540a94b328e0879379e2431ed.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
#include
#include <glad/glad.h>
#include <GLFW/glfw3.h>
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
/*
顶点着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
使用in关键字,在顶点着色器中声明所有的输入顶点属性
layout (location = 0)设定了输入变量(顶点属性)的位置值;并且后面链接顶点属性设置的时候会通过顶点属性位置值进行绑定
vec3 表示三个分量的值(注意每个值都是浮点数类型)
第二行就是表示在位置0的地方有一个三个分量的输入变量aPos
将输入的三维aPos转换为四维并赋值给全局变量gl_Position
/
const char vertexShaderSource = “#version 330 core\n”
“layout (location = 0) in vec3 aPos;\n”
“void main()\n”
“{\n”
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
“}\0”;
/*
片段着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
out 表示输出变量 四维向量的变量FragColor
暂时自定义为 一个Alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。
RGBA的四分量向量
片段着色器所做的是计算像素最后的颜色输出。为了让事情更简单暂时自定义为 我们的片段着色器将会一直输出橘黄色。
/
const char fragmentShaderSource = “#version 330 core\n”
“out vec4 FragColor;\n”
“void main()\n”
“{\n”
" FragColor = vec4(1.0f, 0.2f, 0.2f, 1.0f);\n"
“}\n\0”;
int main()
{
/1、 初始化opengl窗口***************/
//glfw 初始化和配置
glfwInit();//初始化GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//子版本号
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//指定哪个配置文件配置上下文:GLFW我们使用的是核心模式
#ifdef APPLE//如果时mac os xp等系统则要进行配置一下才能生效
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//glfw创建窗口
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//GLFW将我们窗口的上下文设置为当前线程的主上下文
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//GLAD加载所有的opengl函数指针
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
/******************************2、 着色器编译编译链接 *********************************************/
//编写 编译顶点着色器
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);//传入GL_VERTEX_SHADER表示创建顶点着色器
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(vertexShader);//编译
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
cout << "ERROR:Shader::Vertex::Compilation Fail\n" << infoLog << endl;
}
//编写 编译片段着色器
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);//传入GL_FRAGMENT_SHADER 表示创建片段着色器
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(fragmentShader);//编译
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glad_glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
cout << "ERROR:Shader::fragment::Compilation Fail:" << infoLog << endl;
}
//链接着色器程序
unsigned int shaderProgram = glCreateProgram(); //创建着色器程序
glAttachShader(shaderProgram, vertexShader);//之前编译的着色器附加到程序对象上
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);//链接它们
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);//检查程序是否链接报错
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
cout << "ERROR:Program::shaderProgram::Link Fail:" << infoLog << endl;
}
glDeleteShader(vertexShader);//着色器程序已链接完毕则不再需要可以进行delete了
glDeleteShader(fragmentShader);
/******************************3、 顶点属性缓存这些 *********************************************/
//设置顶点数据 和顶点缓存对象 以及配置顶点属性
//标准化设备坐标 顶点
float vertices[] = {
0.5f, 0.5f, 0.0f, // top right
0.5f, -0.5f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f // top left
};
//索引数组
unsigned int indices[] = { // note that we start from 0!
0, 1, 3, // first Triangle
1, 2, 3 // second Triangle
};
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO);//创建一个顶点数组 与顶点属性相绑定
glGenBuffers(1, &VBO);//创建顶点缓冲对象
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);//绑定顶点数组 配置顶点属性
glBindBuffer(GL_ARRAY_BUFFER, VBO);//将GL_ARRAY_BUFFER类型的缓存与VBO绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//之前定义的顶点数据复制到缓冲的内存
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//将GL_ELEMENT_ARRAY_BUFFER类型的缓冲与EBO绑定
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//把索引复制到缓冲里
/*
0;指定我们要配置的顶点属性 就是顶点着色器里面location那个
*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);
glEnableVertexAttribArray(0);//以顶点属性位置值0作为参数,启用顶点属性
glBindBuffer(GL_ARRAY_BUFFER, 0);//VBO 已经与顶点属性数组VAO进行绑定了 那么GL_ARRAY_BUFFER就可以解除绑定
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //记住:不要在VAO激活时解除绑定EBO,因为绑定的元素缓冲区对象存储在VAO中;保持EBO绑定。
glBindVertexArray(0);//您可以在之后解除绑定VAO,这样其他VAO调用就不会意外地修改这个VAO
//渲染循环
//程序在我们主动关闭它之前不断绘制图像并能够接受用户输入 GLFW退出前一直保持运行
while (!glfwWindowShouldClose(window))//检查一次GLFW是否被要求退出
{
//可接收键盘输入esc从而退出
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //设置状态函数
glClear(GL_COLOR_BUFFER_BIT);//使用状态函数
glUseProgram(shaderProgram);//使用着色器程序
glBindVertexArray(VAO);//绑定顶点数组 就是使用顶点属性
//glDrawArrays(GL_TRIANGLES, 0, 3);
//配置OpenGL如何绘制图元。第一个参数表示我们打算将其应用到所有的三角形的正面和背面,第二个参数告诉我们用线来绘制
//注意如果不进行设置glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) 那么就会一直是线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);//使用当前绑定的索引缓冲对象中的索引进行绘制:
glfwSwapBuffers(window);//交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
glfwPollEvents();//检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
//释放/删除之前的分配的所有资源
glfwTerminate();
return 0;
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//会返回这个按键是否正在被按下
glfwSetWindowShouldClose(window, true);//把WindowShouldClose属性设置为 true的方法关闭GLFW
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
//左上角坐标xy和宽高
glViewport(0, 0, width, height);//OpenGL的显示试图
}
## 3.3、两种方法绘制相连的两个三角形
使用六个顶点的方法
使用五个顶点,索引缓冲的方法
![在这里插入图片描述](https://img-blog.csdnimg.cn/2f0c7b8c37e543b58f8cedc41b74900c.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
使用两个顶点数组使用不同的VAO和VBO的方法
![在这里插入图片描述](https://img-blog.csdnimg.cn/8f6ab172bf0241008edf57f52aa14cc2.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
#include
#include <glad/glad.h>
#include <GLFW/glfw3.h>
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
/*
顶点着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
使用in关键字,在顶点着色器中声明所有的输入顶点属性
layout (location = 0)设定了输入变量(顶点属性)的位置值;并且后面链接顶点属性设置的时候会通过顶点属性位置值进行绑定
vec3 表示三个分量的值(注意每个值都是浮点数类型)
第二行就是表示在位置0的地方有一个三个分量的输入变量aPos
将输入的三维aPos转换为四维并赋值给全局变量gl_Position
/
const char vertexShaderSource = “#version 330 core\n”
“layout (location = 0) in vec3 aPos;\n”
“void main()\n”
“{\n”
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
“}\0”;
/*
片段着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
out 表示输出变量 四维向量的变量FragColor
暂时自定义为 一个Alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。
RGBA的四分量向量
片段着色器所做的是计算像素最后的颜色输出。为了让事情更简单暂时自定义为 我们的片段着色器将会一直输出橘黄色。
/
const char fragmentShaderSource = “#version 330 core\n”
“out vec4 FragColor;\n”
“void main()\n”
“{\n”
" FragColor = vec4(1.0f, 0.2f, 0.2f, 1.0f);\n"
“}\n\0”;
int main()
{
/1、 初始化opengl窗口***************/
//glfw 初始化和配置
glfwInit();//初始化GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//子版本号
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//指定哪个配置文件配置上下文:GLFW我们使用的是核心模式
#ifdef APPLE//如果时mac os xp等系统则要进行配置一下才能生效
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//glfw创建窗口
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//GLFW将我们窗口的上下文设置为当前线程的主上下文
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//GLAD加载所有的opengl函数指针
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
/******************************2、 着色器编译编译链接 *********************************************/
//编写 编译顶点着色器
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);//传入GL_VERTEX_SHADER表示创建顶点着色器
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(vertexShader);//编译
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
cout << "ERROR:Shader::Vertex::Compilation Fail\n" << infoLog << endl;
}
//编写 编译片段着色器
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);//传入GL_FRAGMENT_SHADER 表示创建片段着色器
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(fragmentShader);//编译
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glad_glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
cout << "ERROR:Shader::fragment::Compilation Fail:" << infoLog << endl;
}
//链接着色器程序
unsigned int shaderProgram = glCreateProgram(); //创建着色器程序
glAttachShader(shaderProgram, vertexShader);//之前编译的着色器附加到程序对象上
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);//链接它们
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);//检查程序是否链接报错
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
cout << "ERROR:Program::shaderProgram::Link Fail:" << infoLog << endl;
}
glDeleteShader(vertexShader);//着色器程序已链接完毕则不再需要可以进行delete了
glDeleteShader(fragmentShader);
/******************************3、 顶点属性缓存这些 *********************************************/
//设置顶点数据 和顶点缓存对象 以及配置顶点属性
//标准化设备坐标 顶点 绘制矩形
//float vertices[] = {
// 0.5f, 0.5f, 0.0f, // top right
// 0.5f, -0.5f, 0.0f, // bottom right
// -0.5f, -0.5f, 0.0f, // bottom left
// -0.5f, 0.5f, 0.0f // top left
//};
索引数组
//unsigned int indices[] = { // note that we start from 0!
// 0, 1, 3, // first Triangle
// 1, 2, 3 // second Triangle
//};
//绘制两个相连的三角形
float firstTriangle[] = {
-0.9f, -0.5f, 0.0f, // left
-0.0f, -0.5f, 0.0f, // right
-0.45f, 0.5f, 0.0f, // top
};
float secondTriangle[] = {
0.0f, -0.5f, 0.0f, // left
0.9f, -0.5f, 0.0f, // right
0.45f, 0.5f, 0.0f // top
};
unsigned int VBO[2], VAO[2];
glGenVertexArrays(2, VAO);//创建一个顶点数组 与顶点属性相绑定
glGenBuffers(2, VBO);//创建顶点缓冲对象
glBindVertexArray(VAO[0]);//绑定顶点数组 配置顶点属性
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);//将GL_ARRAY_BUFFER类型的缓存与VBO绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(firstTriangle), firstTriangle, GL_STATIC_DRAW);//之前定义的顶点数据复制到缓冲的内存
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);
glEnableVertexAttribArray(0);//以顶点属性位置值0作为参数,启用顶点属性
glBindVertexArray(VAO[1]);//绑定顶点数组 配置顶点属性
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);//将GL_ARRAY_BUFFER类型的缓存与VBO绑定
glBufferData(GL_ARRAY_BUFFER, sizeof(secondTriangle), secondTriangle, GL_STATIC_DRAW);//之前定义的顶点数据复制到缓冲的内存
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);//可以传入0 由opengl自动计算偏移量
glEnableVertexAttribArray(0);//以顶点属性位置值0作为参数,启用顶点属性
//渲染循环
//程序在我们主动关闭它之前不断绘制图像并能够接受用户输入 GLFW退出前一直保持运行
while (!glfwWindowShouldClose(window))//检查一次GLFW是否被要求退出
{
//可接收键盘输入esc从而退出
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //设置状态函数
glClear(GL_COLOR_BUFFER_BIT);//使用状态函数
glUseProgram(shaderProgram);//使用着色器程序
glBindVertexArray(VAO[0]);//绑定顶点数组 就是使用顶点属性
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(VAO[1]);//绑定顶点数组 就是使用顶点属性
glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window);//交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上。
glfwPollEvents();//检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数
}
glDeleteVertexArrays(2, VAO);
glDeleteBuffers(2, VBO);
glDeleteProgram(shaderProgram);
//释放/删除之前的分配的所有资源
glfwTerminate();
return 0;
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)//会返回这个按键是否正在被按下
glfwSetWindowShouldClose(window, true);//把WindowShouldClose属性设置为 true的方法关闭GLFW
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
//左上角坐标xy和宽高
glViewport(0, 0, width, height);//OpenGL的显示试图
}
## 3.4、使用两个着色器输出不同颜色的三角形
![在这里插入图片描述](https://img-blog.csdnimg.cn/981b39ad4caf45b09ee69276803c6dbc.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p3MTk5Ng==,size_16,color_FFFFFF,t_70#pic_center)
#include
#include <glad/glad.h>
#include <GLFW/glfw3.h>
using namespace std;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
/*
顶点着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
使用in关键字,在顶点着色器中声明所有的输入顶点属性
layout (location = 0)设定了输入变量(顶点属性)的位置值;并且后面链接顶点属性设置的时候会通过顶点属性位置值进行绑定
vec3 表示三个分量的值(注意每个值都是浮点数类型)
第二行就是表示在位置0的地方有一个三个分量的输入变量aPos
将输入的三维aPos转换为四维并赋值给全局变量gl_Position
/
const char vertexShaderSource = “#version 330 core\n”
“layout (location = 0) in vec3 aPos;\n”
“void main()\n”
“{\n”
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
“}\0”;
/*
片段着色器GLSL源码
GLSL版本号和OpenGL的版本是匹配的,使用openGL3.3版本则使用GLSL的330
out 表示输出变量 四维向量的变量FragColor
暂时自定义为 一个Alpha值为1.0(1.0代表完全不透明)的橘黄色的vec4赋值给颜色输出。
RGBA的四分量向量
片段着色器所做的是计算像素最后的颜色输出。为了让事情更简单暂时自定义为 我们的片段着色器将会一直输出橘黄色。
/
const char fragmentShaderSource = “#version 330 core\n”
“out vec4 FragColor;\n”
“void main()\n”
“{\n”
" FragColor = vec4(1.0f, 0.2f, 0.2f, 1.0f);\n"
“}\n\0”;
const char* fragmentShaderSourceTwo = “#version 330 core\n”
“out vec4 FragColor;\n”
“void main()\n”
“{\n”
" FragColor = vec4(1.0f, 1.0f, 0.0f, 1.0f);\n"
“}\n\0”;
int main()
{
/1、 初始化opengl窗口***************/
//glfw 初始化和配置
glfwInit();//初始化GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//主版本号
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//子版本号
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);//指定哪个配置文件配置上下文:GLFW我们使用的是核心模式
#ifdef APPLE//如果时mac os xp等系统则要进行配置一下才能生效
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
//glfw创建窗口
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);//GLFW将我们窗口的上下文设置为当前线程的主上下文
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//GLAD加载所有的opengl函数指针
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
/******************************2、 着色器编译编译链接 *********************************************/
//编写 编译顶点着色器
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);//传入GL_VERTEX_SHADER表示创建顶点着色器
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(vertexShader);//编译
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
cout << "ERROR:Shader::Vertex::Compilation Fail\n" << infoLog << endl;
}
链接一个着色器 输出橘黄色///
//编写 编译片段着色器
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);//传入GL_FRAGMENT_SHADER 表示创建片段着色器
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);//绑定源码 1表示只有一个
glCompileShader(fragmentShader);//编译
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glad_glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
cout << "ERROR:Shader::fragment::Compilation Fail:" << infoLog << endl;
}
//链接着色器程序
unsigned int shaderProgram = glCreateProgram(); //创建着色器程序
glAttachShader(shaderProgram, vertexShader);//之前编译的着色器附加到程序对象上
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);//链接它们
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);//检查程序是否链接报错
if (!success)
{
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
cout << "ERROR:Program::shaderProgram::Link Fail:" << infoLog << endl;
}
/链接一个着色器 输出黄色//
unsigned int fragmentShaderYellow = glCreateShader(GL_FRAGMENT_SHADER);//传入GL_FRAGMENT_SHADER 表示创建片段着色器
glShaderSource(fragmentShaderYellow, 1, &fragmentShaderSourceTwo, NULL);//绑定源码 1表示只有一个
glCompileShader(fragmentShaderYellow);//编译
glGetShaderiv(fragmentShaderYellow, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glad_glGetShaderInfoLog(fragmentShaderYellow, 512, NULL, infoLog);
cout << "ERROR:Shader::fragment::Compilation Fail:" << infoLog << endl;
}
//链接着色器程序
unsigned int shaderProgramYellow = glCreateProgram(); //创建着色器程序
glAttachShader(shaderProgramYellow, vertexShader);//之前编译的着色器附加到程序对象上
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
fragmentShaderSourceTwo, NULL);//绑定源码 1表示只有一个
glCompileShader(fragmentShaderYellow);//编译
glGetShaderiv(fragmentShaderYellow, GL_COMPILE_STATUS, &success);//检查是否编译报错 也就是检查GLSL的语法
if (!success)
{
glad_glGetShaderInfoLog(fragmentShaderYellow, 512, NULL, infoLog);
cout << “ERROR:Shader::fragment::Compilation Fail:” << infoLog << endl;
}
//链接着色器程序
unsigned int shaderProgramYellow = glCreateProgram(); //创建着色器程序
glAttachShader(shaderProgramYellow, vertexShader);//之前编译的着色器附加到程序对象上
[外链图片转存中…(img-IbaIFFYC-1715839422928)]
[外链图片转存中…(img-8qGR3fJ9-1715839422929)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新