#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include<iostream>
using namespace std;
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
//这里我们检查用户是否按下了返回键(Esc)
}
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 // 第二个三角形
};
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"// 位置变量的属性位置值为0
"out vec4 vertexColor;\n"// 为片段着色器指定一个颜色输出
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
" vertexColor = vec4(0.5, 0.0, 0.0, 1.0); \n"// 把输出变量设置为暗红色
"}\0";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor;\n" //使用uniform关键字创建创建一个全局变量 Uniform是一种从CPU中的应用向GPU中的着色器发送数据的方式
"void main()\n"
"{\n"
" FragColor = ourColor;\n"//把输出的颜色设为 uniform变量的颜色
"}\n";
//const char* fragmentShaderSource =
//"#version 330 core\n"
//"out vec4 FragColor;\n"
//"in vec4 vertexColor;\n" // 从顶点着色器传来的输入变量(名称相同、类型相同)
//"void main()\n"
//"{\n"
//" FragColor = vertexColor;\n"
//"}\n";
int main(void)
{
//必须先初始化该库,然后才能使用大多数GLFW函数。成功初始化后,GLFW_TRUE将返回。如果发生错误,GLFW_FALSE则返回。
if (!glfwInit())
return -1;
//创建窗口(OpenGL上下文似乎也一并创建了)
GLFWwindow* window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
//glfwCreateWindow函数需要窗口的宽和高作为它的前两个参数。第三个参数表示这个窗口的名称(标题
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
//使用GLAD来加载OpenGL的函数地址 GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。
//我们给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数。GLFW给我们的是glfwGetProcAddress,它根据我们编译的系统定义了正确的函数。
gladLoadGL();
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
unsigned int vertexShader;//创建一个对象vertexShader 以ID来索引所以使用 unsigned int型
vertexShader = glCreateShader(GL_VERTEX_SHADER);//glCreateShader来创建shader 以参数形式告诉函数GL_VERTEX_SHADER 顶点做色器
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//下一步我们把这个着色器源码附加到着色器对象上,然后编译它:
glCompileShader(vertexShader);
/*
glShaderSource函数把要编译的着色器对象作为第一个参数。第二参数指定了传递的源码字符串数量,
这里只有一个。第三个参数是顶点着色器真正的源码,第四个参数我们先设置为NULL。
*/
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
/*
这个片段着色器和定点着色器一样
*/
//将源码编译之后需要把两个源码链接到一个程序里面
unsigned int shaderProgram;
shaderProgram = glCreateProgram();//使用这个glCreateProgram创建一个程序 返回ID的索引
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader); //把两个源码附加到程序上
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader); //调用完成之后删除对象释放内存
glDeleteShader(fragmentShader);
/*
VBO顶点缓冲对象 作用为管理内存 用来管理在GPU上创建内存用于储存我们的顶点数据的内存
定义一个VBO变量 把变量传入glGenBuffers缓冲生成函数里面产生一个缓冲和一个ID
然后把这个缓冲对象用来管理GL_ARRAY_BUFFER
*/
//如果要绘制两个三角形就需要使用索引缓存对象来告诉GPU使用哪些顶点
unsigned int VAO, VBO;
unsigned int EBO;
glGenBuffers(1, &EBO);//glGenBuffers创建索引对象
glGenVertexArrays(1, &VAO);//glGenVertexArrays来创建顶点数组
glGenBuffers(1, &VBO);//glGenBuffers来创建缓存
glBindVertexArray(VAO);//为下面的属性绑定VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); //OpenGL有很多缓冲对象类型,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//绑定顶点并把顶点发送给GPU 第三个参数就是我们希望发送的实际数据。
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//绑定EBO
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//如何使用索引
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//GPU有了顶点之后使用这个函数来链接顶点属性glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);//解绑V
glBindVertexArray(0);//使用完成之后解绑就行了为下面的属性绑定VAO
//循环直到用户关闭窗口 渲染循环(Render Loop),它能在我们让GLFW退出前一直保持运行
while (!glfwWindowShouldClose(window))
{
processInput(window);//使用按键
//清理屏幕所用的颜色:
glClearColor(0.4f, 0.5f, 0.6f, 1.0f);
//清理屏幕 它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲,
//可能的缓冲位有GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。由于现在我们只关心颜色值,所以我们只清空颜色缓冲。
glClear(GL_COLOR_BUFFER_BIT);
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//使用glPolygonMode设置绘制模式这里是绘制线框
glUseProgram(shaderProgram);//使用这个程序
// 更新uniform颜色
float timeValue = glfwGetTime(); //首先我们通过glfwGetTime()获取运行的秒数。
float greenValue = sin(timeValue) / 2.0f + 0.5f;//然后我们使用sin函数让颜色在0.0到1.0之间改变,最后将结果储存到greenValue里。
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");//查询函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)如果glGetUniformLocation返回-1就代表没有找到这个位置值。
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 0.5f);//第一个参数Location 后面依次是RGB颜色 RED GREEN BLUE
//绘制三角形
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glDrawArrays(GL_TRIANGLES, 0, 3);
//交换前后缓冲
glfwSwapBuffers(window);
//轮询并处理事件
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
//使用GLFW完成操作后,通常是在应用程序退出之前,需要终止GLFW 释放/删除之前的分配的所有资源
glfwTerminate();
return 0;
}
最后效果随时间变换而变化
更多属性
//多属性的使用
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include<iostream>
using namespace std;
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
//这里我们检查用户是否按下了返回键(Esc)
}
float vertices[] = {
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // 顶部
};
//根据索引直来绘制图形
unsigned int indices[] = { // 注意索引从0开始!
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
const char* vertexShaderSource =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"// 位置变量的属性位置值为0
"layout (location = 1) in vec3 aColor;\n"// 颜色变量的属性位置为1
"out vec3 ourColor;\n"// 为片段着色器指定一个颜色输出
"void main()\n"
"{\n"
" gl_Position = vec4(aPos,1.0);\n"
" ourColor = aColor; \n"// 把输出变量设置为暗红色
"}\0";
const char* fragmentShaderSource =
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 ourColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(ourColor,1.0);\n"//把输出的颜色设为 uniform变量的颜色
"}\n";
int main(void)
{
//必须先初始化该库,然后才能使用大多数GLFW函数。成功初始化后,GLFW_TRUE将返回。如果发生错误,GLFW_FALSE则返回。
if (!glfwInit())
return -1;
//创建窗口(OpenGL上下文似乎也一并创建了)
GLFWwindow* window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
//glfwCreateWindow函数需要窗口的宽和高作为它的前两个参数。第三个参数表示这个窗口的名称(标题
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
//使用GLAD来加载OpenGL的函数地址 GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。
//我们给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数。GLFW给我们的是glfwGetProcAddress,它根据我们编译的系统定义了正确的函数。
gladLoadGL();
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
unsigned int vertexShader;//创建一个对象vertexShader 以ID来索引所以使用 unsigned int型
vertexShader = glCreateShader(GL_VERTEX_SHADER);//glCreateShader来创建shader 以参数形式告诉函数GL_VERTEX_SHADER 顶点做色器
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);//下一步我们把这个着色器源码附加到着色器对象上,然后编译它:
glCompileShader(vertexShader);
/*
glShaderSource函数把要编译的着色器对象作为第一个参数。第二参数指定了传递的源码字符串数量,
这里只有一个。第三个参数是顶点着色器真正的源码,第四个参数我们先设置为NULL。
*/
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
/*
这个片段着色器和定点着色器一样
*/
//将源码编译之后需要把两个源码链接到一个程序里面
unsigned int shaderProgram;
shaderProgram = glCreateProgram();//使用这个glCreateProgram创建一个程序 返回ID的索引
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader); //把两个源码附加到程序上
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader); //调用完成之后删除对象释放内存
glDeleteShader(fragmentShader);
/*
VBO顶点缓冲对象 作用为管理内存 用来管理在GPU上创建内存用于储存我们的顶点数据的内存
定义一个VBO变量 把变量传入glGenBuffers缓冲生成函数里面产生一个缓冲和一个ID
然后把这个缓冲对象用来管理GL_ARRAY_BUFFER
*/
//如果要绘制两个三角形就需要使用索引缓存对象来告诉GPU使用哪些顶点
unsigned int VAO, VBO;
unsigned int EBO;
glGenBuffers(1, &EBO);//glGenBuffers创建索引对象
glGenVertexArrays(1, &VAO);//glGenVertexArrays来创建顶点数组
glGenBuffers(1, &VBO);//glGenBuffers来创建缓存
glBindVertexArray(VAO);//为下面的属性绑定VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); //OpenGL有很多缓冲对象类型,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//绑定顶点并把顶点发送给GPU 第三个参数就是我们希望发送的实际数据。
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//绑定EBO
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//如何使用索引
//这里配置的是属性位置为0的顶点属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6* sizeof(float), (void*)0);//GPU有了顶点之后使用这个函数来链接顶点属性glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据
glEnableVertexAttribArray(0);
//这里配置的是属性位置为1的顶点属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
/*
* 步长:
由于我们现在有了两个顶点属性,我们不得不重新计算步长值。
为获得数据队列中下一个属性值(比如位置向量的下个x分量)我们必须向右移动6个float,其中3个是位置值,另外3个是颜色值。
这使我们的步长值为6乘以float的字节数(=24字节)。
偏移量:
同样,这次我们必须指定一个偏移量。对于每个顶点来说,位置顶点属性在前,所以它的偏移量是0。
颜色属性紧随位置数据之后,所以偏移量就是3 * sizeof(float),用字节来计算就是12字节。
*/
glBindBuffer(GL_ARRAY_BUFFER, 0);//解绑V
glBindVertexArray(0);//使用完成之后解绑就行了为下面的属性绑定VAO
//循环直到用户关闭窗口 渲染循环(Render Loop),它能在我们让GLFW退出前一直保持运行
while (!glfwWindowShouldClose(window))
{
processInput(window);//使用按键
//清理屏幕所用的颜色:
glClearColor(0.4f, 0.5f, 0.6f, 1.0f);
//清理屏幕 它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲,
//可能的缓冲位有GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。由于现在我们只关心颜色值,所以我们只清空颜色缓冲。
glClear(GL_COLOR_BUFFER_BIT);
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//使用glPolygonMode设置绘制模式这里是绘制线框
glUseProgram(shaderProgram);//使用这个程序
// 更新uniform颜色
float timeValue = glfwGetTime(); //首先我们通过glfwGetTime()获取运行的秒数。
float greenValue = sin(timeValue) / 2.0f + 0.5f;//然后我们使用sin函数让颜色在0.0到1.0之间改变,最后将结果储存到greenValue里。
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");//查询函数提供着色器程序和uniform的名字(这是我们希望获得的位置值的来源)如果glGetUniformLocation返回-1就代表没有找到这个位置值。
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 0.5f);//第一个参数Location 后面依次是RGB颜色 RED GREEN BLUE
//绘制三角形
glBindVertexArray(VAO);
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//第二个参数是我们打算绘制顶点的个数,这里填6,也就是说我们一共需要绘制6个顶点。
glDrawArrays(GL_TRIANGLES, 0, 3);
//交换前后缓冲
glfwSwapBuffers(window);
//轮询并处理事件
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
//使用GLFW完成操作后,通常是在应用程序退出之前,需要终止GLFW 释放/删除之前的分配的所有资源
glfwTerminate();
return 0;
}
创建shader类来管理着色器
shader.h头文件
#include <glad/glad.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char* vertexPath, const char* fragmentPath)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
// 打开文件
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// 读取文件的缓冲内容到数据流中
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// 关闭文件处理器
vShaderFile.close();
fShaderFile.close();
// 转换数据流到string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ: " << e.what() << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char* fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string& name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string& name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string& name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
shader.cpp实现
#include "Shader.h"
#include <GLFW/glfw3.h>
float vertices[] = {
// positions // colors
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // bottom left
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // top
};
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
//这里我们检查用户是否按下了返回键(Esc)
}
int main(void)
{
//必须先初始化该库,然后才能使用大多数GLFW函数。成功初始化后,GLFW_TRUE将返回。如果发生错误,GLFW_FALSE则返回。
if (!glfwInit())
return -1;
//创建窗口(OpenGL上下文似乎也一并创建了)
GLFWwindow* window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
//glfwCreateWindow函数需要窗口的宽和高作为它的前两个参数。第三个参数表示这个窗口的名称(标题
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
//使用GLAD来加载OpenGL的函数地址 GLAD是用来管理OpenGL的函数指针的,所以在调用任何OpenGL的函数之前我们需要初始化GLAD。
//我们给GLAD传入了用来加载系统相关的OpenGL函数指针地址的函数。GLFW给我们的是glfwGetProcAddress,它根据我们编译的系统定义了正确的函数。
gladLoadGL();
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
Shader ourShader("shader.vs", "shader.fs");
//如果要绘制两个三角形就需要使用索引缓存对象来告诉GPU使用哪些顶点
unsigned int VAO, VBO;
unsigned int EBO;
glGenBuffers(1, &EBO);//glGenBuffers创建索引对象
glGenVertexArrays(1, &VAO);//glGenVertexArrays来创建顶点数组
glGenBuffers(1, &VBO);//glGenBuffers来创建缓存
glBindVertexArray(VAO);//为下面的属性绑定VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); //OpenGL有很多缓冲对象类型,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//绑定顶点并把顶点发送给GPU 第三个参数就是我们希望发送的实际数据。
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);//绑定EBO
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//如何使用索引
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);//GPU有了顶点之后使用这个函数来链接顶点属性glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3* sizeof(float)));//GPU有了顶点之后使用这个函数来链接顶点属性glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);//解绑V
glBindVertexArray(0);//使用完成之后解绑就行了为下面的属性绑定VAO
//循环直到用户关闭窗口 渲染循环(Render Loop),它能在我们让GLFW退出前一直保持运行
while (!glfwWindowShouldClose(window))
{
processInput(window);//使用按键
//清理屏幕所用的颜色:
glClearColor(0.4f, 0.5f, 0.6f, 1.0f);
//清理屏幕 它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲,
//可能的缓冲位有GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。由于现在我们只关心颜色值,所以我们只清空颜色缓冲。
glClear(GL_COLOR_BUFFER_BIT);
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//使用glPolygonMode设置绘制模式这里是绘制线框
ourShader.use();//使用这个程序
glBindVertexArray(VAO);
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
//交换前后缓冲
glfwSwapBuffers(window);
//轮询并处理事件
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
//使用GLFW完成操作后,通常是在应用程序退出之前,需要终止GLFW 释放/删除之前的分配的所有资源
glfwTerminate();
return 0;
}
把着色器代码放到资源文件下面
//片段着色器
#version 330 core
out vec4 fragColor;
in vec3 ourColor;
void main()
{
fragColor = vec4(ourColor,1.0);
}
//顶点着色器
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 ourColor;
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor;
}