OpenGl个人笔记

目录

一、创建窗口

二、创建三角

三、着色器

四、纹理贴图


一、创建窗口

1.前提:

需要下载并配置好GLFW(GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最低限度的接口)

需要下载并配置好GLAD(GLAD可以使OpenGL基础渲染变得十分简单,只需要简单四个步骤就可以完成基础渲染。)

配置步骤:

下载:

GLAD在线下载

 ps:各种库的不同作用

2.创建窗口(如果直接全部赋值learngl 的全部代码似乎有问题 这里就先不按照原文写)

#include<iostream>
#include <GL/glew.h>
#include<GLFW\glfw3.h>




using namespace std;

int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);

	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		
		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);

		//获取用户按得按键(?)
		glfwPollEvents();
	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

这里我有个坑,查了好久才找到解决办法

 原因是

opengl调用的glew分为动态库和静态库,当你在链接器中添加的是glew32s.lib时,说明你编译的是静态库。此时你要在#include <GL/glew.h>前添加 #define GLEW_STATIC。

所以加上个#define GLEW_STATIC的就可以了

 3.在上面我们获得了鼠标的输入但我们并没有应用他

这里可以加上按下ESC退出程序

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>


using namespace std;

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);

	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		
		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);

		//获取用户按得按键(?)
		glfwPollEvents();

		processInput(window);
	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

4.渲染

之前里面全是黑色的太丑了 我们加点不一样的

思路:

只是为了测试事情是否真的有效,我们想用我们选择的颜色清除屏幕(用指定颜色来清屏)。 在帧开始时,我们要清除屏幕。 否则我们仍然会看到前一帧的结果(这可能是您正在寻找的效果,但通常您不会)。 我们可以使用清除屏幕的颜色缓冲区 清除 我们在其中传递缓冲区位以指定我们要清除的缓冲区。 我们可以设置的可能位是 GL_COLOR_BUFFER_BIT 、 GL_DEPTH_BUFFER_BIT 和 GL_STENCIL_BUFFER_BIT 。 现在我们只关心颜色值,所以我们只清除颜色缓冲区。

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>


using namespace std;

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);

	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();

		
	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

二、创建三角

前言:创建一个三角形并没有我们想象的那么简单,需要明白在opengl中VAO和VBO 的区别

更具体的解释在这篇文章 OpenGL开发关于VAO和VBO的理解

个人理解是:

  • 先创建缓冲对象(VBO),然后设置缓冲对象的缓冲类型 并激活
  • 将准备好的顶点数据复制到缓冲的内存中

此时我们数据在内存中是这样的:

 但是此时机器不知道这些数据到底代表什么意思

  • 指定输入数据的哪一个部分对应顶点着色器的哪一个顶点属性,也就是在渲染前指定OpenGL该如何解释VBO中的顶点数据。

 有个问题:

VBO保存了一个模型的顶点属性信息,每次绘制模型之前需要绑定顶点的所有信息,当数据量很大时,重复这样的动作变得非常麻烦。

 引入VAO:

  • VAO可以把这些所有的配置都存储在一个对象中,每次绘制模型时,只需要绑定这个VAO对象就可以了,每个模型一般都有一个VAO。

 (可否理解为VAO保存了VBO里数据的索引)

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
using namespace std;
float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f
};
void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);

	//glGenVertexArrays可以产生多个 但我们这里只定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1,&VAO);
	glBindVertexArray(VAO);

	//定义ABO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER,VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

(此时运行是没有错误的 但是也不会显示三角形,因为还没加上我们的shader)

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
using namespace std;
float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f
};

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";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{ FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); }\n";

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);

#pragma region 第一步
	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
#pragma endregion 第一步


#pragma region 第二步
	//创建顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	//创建偏远着色器
	unsigned int fragmentSahder;
	fragmentSahder = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentSahder, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentSahder);
#pragma endregion 第二步

#pragma region 第三步
	//把这两个shader组装成一整个的着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	//我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentSahder);
	glLinkProgram(shaderProgram);
#pragma endregion 第三步

#pragma region 第四步
	//创建一个0号栏位 每三个为一组(向量),每个栏位都是一个浮点数,不需要归一化,挖完三个float再去下一个顶点
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
#pragma endregion 第四步
	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
#pragma region 第五步
		glBindVertexArray(VAO);
		glUseProgram(shaderProgram);
		glDrawArrays(GL_TRIANGLES, 0, 3);
#pragma endregion 第五步
		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

当当当~我们的三角形已经出来了

这个时候我们尝试来改造下我们上面的方法

期待他可以画出一个多边形

 

(这里有个问题,点的顺序应该为逆时针的,最后三行明明反了,但我们依然有效的现实出来,

这是因为opengl在这里没有帮我们背面剔除)

我们自己加一个背面剔除

 此时我们发现了明明四边形四个点 但这里为什么要有六个向量数据呢?

因为四边形有两个三角形 所以一共六个点,这样会不会有点浪费?

我们接下来来解决这个问题

这里我们引入索引的概念

 这样我们只用索引就可以表示我们想用那些点了

推荐一篇博文,博主把VAO VBO EBO说的很明白

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
using namespace std;
float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f,
	 0.8f,  0.8f, 0.0f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0, 1, 2, // 第一个三角形
	2, 1, 3  // 第二个三角形
};

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";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{ FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); }\n";

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

#pragma region 第一步
	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
#pragma endregion 第一步


#pragma region 第二步
	//创建顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	//创建偏远着色器
	unsigned int fragmentSahder;
	fragmentSahder = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentSahder, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentSahder);
#pragma endregion 第二步

#pragma region 第三步
	//把这两个shader组装成一整个的着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	//我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentSahder);
	glLinkProgram(shaderProgram);
#pragma endregion 第三步

#pragma region 第四步
	//创建一个0号栏位 每三个为一组(向量),每个栏位都是一个浮点数,不需要归一化,挖完三个float再去下一个顶点
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
#pragma endregion 第四步
	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
#pragma region 第五步
		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glUseProgram(shaderProgram);
		/*glDrawArrays(GL_TRIANGLES, 0, 6);*/
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
#pragma endregion 第五步
		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

三、着色器

具体讲下着色器代码

//这段着色器代码是给什么版本的OpenGl用的
#version version_number
//GPU里的输入
in type in_variable_name;
in type in_variable_name;
//GPU里的输出
out type out_variable_name;
//从Cpu传进来的信息
uniform type uniform_name;

int main()
{
  // 处理输入并进行一些图形操作
  ...
  // 输出处理过的结果到输出变量
  out_variable_name = weird_stuff_we_processed;
}

我们用到的数据是从哪里来的:

在上一节我们已经用到了着色器,这里稍作概括下

一、
生成VAO glGenVertexArrays
执行VAO绑定 glBindVertexArray

先开辟显存空间 填入VBO的ID(int)glGenBuffers
然后再绑定(Bind)一个显存缓冲 glBindBuffe
将顶点数据传到显存缓冲中glBufferData

二、
//------现在我们已经把顶点数据储存在显卡的内存中(CPU->GPU),现在我们用着色器来真正的使用这些数据------//
//着色器就是运行在GPU上的小程序
//顶点着色器是一个小程序 片元着色器也是一个小程序等等
//每个小程序都是渲染管线的一部分

因为创建着色器过程大体相似,现在我们来顶点着色器作为例子
创建着色器:glCreateShader
把着色器源码附到着色器上glShaderSource
编译glCompileShader

三、
//--------现在我们可以把我们创建的两个着色器链接起来成为着色器程序了
//着色器程序对象(Shader Program Object)是多个着色器合并之后并最终链接完成的版本。
//如果要使用刚才编译的着色器我们必须把它们链接(Link)为一个着色器程序对象,
//然后在渲染对象的时候激活这个着色器程序。已激活着色器程序的着色器将在我们发送渲染调用的时候被使用

创建着色器程序glCreateProgram
把之前写的着色器附加到我们着色器程序上glAttachShader
链接一下glLinkProgram
激活着色器程序 glUseProgram
删除之前的着色器 glDeleteShader

四、
接下来就是如何解释传入的数据glVertexAttribPointer

五、
绘画glDrawArrays

现在来点小训练,生成大红色的一个形状

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
using namespace std;
float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f,
	 0.8f,  0.8f, 0.0f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0, 1, 2, // 第一个三角形
	2, 1, 3  // 第二个三角形
};

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"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"
"in vec4 vertexColor;                                \n"
"out vec4 FragColor;\n"
"void main()\n"
"{ FragColor = vertexColor; }\n";

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

#pragma region 第一步
	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
#pragma endregion 第一步


#pragma region 第二步
	//创建顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	//创建偏远着色器
	unsigned int fragmentSahder;
	fragmentSahder = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentSahder, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentSahder);
#pragma endregion 第二步

#pragma region 第三步
	//把这两个shader组装成一整个的着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	//我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentSahder);
	glLinkProgram(shaderProgram);
#pragma endregion 第三步

#pragma region 第四步
	//创建一个0号栏位 每三个为一组(向量),每个栏位都是一个浮点数,不需要归一化,挖完三个float再去下一个顶点
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
#pragma endregion 第四步
	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
#pragma region 第五步
		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glUseProgram(shaderProgram);
		/*glDrawArrays(GL_TRIANGLES, 0, 6);*/
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
#pragma endregion 第五步
		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

我们想要使用cpu里面的值

第一节我们大体学习了opengl绘画的流程
取得数据->把数据放到着色器程序里进行操作
现在我们具体来玩一下着色器这个小玩意

关于着色器的内容上一节已经有了解了,这里只需要注意下
着色器语言是GLSL  并且基本上每个着色器都有输入输出
顶点着色器 输入:in vec3 aPos; 输出 out vec4 vertexColor;
片元着色器 输入:in vec4 vertexColor; 输出 out vec4 FragColor;

我们主要来说一下Uniform
我们想要再CPU和GPU之间进行通信 就需要靠它!

先在片元着色器中声明一个uniform:
uniform vec4 ourColor
用来当做我们颜色的输出

现在我们可以在外部修改这个值了
float timeValue = glfwGetTime();
float greenValue = (sin(timeValue) / 2.0f) + 0.5f;
//获取uniform
int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
//更新一个uniform之前你必须先调用glUseProgram
glUseProgram(shaderProgram);
//设置/更新uniform
glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

 现在我们就拥有可以变换颜色的多边形了

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
using namespace std;
float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f,
	 0.8f,  0.8f, 0.0f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0, 1, 2, // 第一个三角形
	2, 1, 3  // 第二个三角形
};

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"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"
"in vec4 vertexColor;                                \n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor; \n"
"void main()\n"
"{ FragColor = ourColor; }\n";

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

#pragma region 第一步
	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
#pragma endregion 第一步


#pragma region 第二步
	//创建顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	//创建偏远着色器
	unsigned int fragmentSahder;
	fragmentSahder = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentSahder, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentSahder);
#pragma endregion 第二步

#pragma region 第三步
	//把这两个shader组装成一整个的着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	//我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentSahder);
	glLinkProgram(shaderProgram);
#pragma endregion 第三步

#pragma region 第四步
	//创建一个0号栏位 每三个为一组(向量),每个栏位都是一个浮点数,不需要归一化,挖完三个float再去下一个顶点
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
#pragma endregion 第四步
	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);


		// 更新uniform颜色
		float timeValue = glfwGetTime();
		float greenValue = sin(timeValue) / 2.0f + 0.5f;
		int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
		glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

		glUseProgram(shaderProgram);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

//__________________//

基础的复习就到这里,现在我们向VBO,里填入更多的属性

现在VBO里是这样

 但是等等,这样会不会有点复杂?

我们可以把它分开

 现在我们有了两组数据了,意味着我们需要创建两组VBO,并且在VAO里创建两个栏位(这里我们用的0和1,这两个标识一定要和下面我们将要创建着色器的标识相对应!)用于解释数据/给数据分类

稍微一提 glVertexAttribPointer的函数最后一个参数是最后一个变量说明了起始位置,这里因为有两个VBO所以起始位置都是0(而不用隔三个),倒数第二个参数是挖一次数据跳几格继续挖

//定义一个VAO
	unsigned int VAO;
    //第一个参数指的是创建VAO的数量
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义VBO
	unsigned int VBO,VBOColor;

	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(verticesPostion), verticesPostion, GL_STATIC_DRAW);//传数据
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//解释传入的数据
	glEnableVertexAttribArray(0);

	glGenBuffers(1, &VBOColor);
	glBindBuffer(GL_ARRAY_BUFFER, VBOColor);
	glBufferData(GL_ARRAY_BUFFER, sizeof(verticesColor), verticesColor, GL_STATIC_DRAW);//传数据
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//解释传入的数据
	glEnableVertexAttribArray(1);

现在数据已经放进缓存里了,现在该用着色器来使用我们的数据了

这里还用到了EBO,记得注意下EBO的顺序,我这里VBO是逆时针放的,VEO组成的三角形也是逆时针组成的

这里画了张图,略微表示下(十年的功底了,见谅)

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
using namespace std;

float verticesPostion[] = {
	0.5f, -0.5f, 0.0f, 
	0.5f, 0.5f, 0.0f,
	 -0.5f,  0.5f, 0.0f, 
	 -0.5f,  -0.5f, 0.0f
};


float verticesColor[] = {
	1.0f, 0.0f, 0.0f,
	0.0f, 1.0f, 0.0f,
	0.0f, 0.0f, 1.0f,
	0.3f,0.5f,0.7f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0, 1, 2, // 第一个三角形
	2, 3, 0  // 第二个三角形
};

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;   \n"
"out vec4 vertexColor;                 \n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);  \n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"in vec4 vertexColor;                                \n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor; \n"
"void main()\n"
"{ FragColor = vertexColor; }\n";

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	//开启面剔除
	glEnable(GL_CULL_FACE);
	//剔除背面
	glCullFace(GL_BACK);


	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义VBO
	unsigned int VBO,VBOColor;

	glGenBuffers(1, &VBO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(verticesPostion), verticesPostion, GL_STATIC_DRAW);//传数据
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//解释传入的数据
	glEnableVertexAttribArray(0);

	glGenBuffers(1, &VBOColor);
	glBindBuffer(GL_ARRAY_BUFFER, VBOColor);
	glBufferData(GL_ARRAY_BUFFER, sizeof(verticesColor), verticesColor, GL_STATIC_DRAW);//传数据
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);//解释传入的数据
	glEnableVertexAttribArray(1);


	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	//创建偏远着色器
	unsigned int fragmentSahder;
	fragmentSahder = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentSahder, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentSahder);

	//把这两个shader组装成一整个的着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	//我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentSahder);
	glLinkProgram(shaderProgram);


	

	

	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);


		// 更新uniform颜色
		float timeValue = glfwGetTime();
		float greenValue = sin(timeValue) / 2.0f + 0.5f;
		int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
		glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

		glUseProgram(shaderProgram);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

总结一下流程:

我们都知道VBO的作用是把数据从内存搬到显卡的缓冲区,着色器程序是将我们搬到缓冲区的数据进行计算渲染成图片,还有个VAO是给VBO传入的数据绑定些属性,让着色器明确哪些数据是颜色,哪些数据是坐标(VAO可以理解为是一个属性的数组,不可以记录具体的数据,VAO是服务与VBO和着色器程序的),稍微提一下EBO可以帮助我们摆脱画四边形但是需要六个点的麻烦局面,我们只需要四个点(四边形四个点很合理嘛!),然后给出多边形里蕴含三角形的索引就可以了

PS:分开写是为了便于理解,但是是以性能为代价的,所以我们还是尽量放在一起,使用一个VBO

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
using namespace std;
float vertices[] = {
	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 
	 0.8f,  0.8f, 0.0f,0.3f,0.5f,0.7f
	//-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 
	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
};
unsigned int indices[] = { // 注意索引从0开始! 
	2, 1, 0, // 第一个三角形
	3, 2, 0  // 第二个三角形
	//0,1,2,
	//2,3,1
};

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;   \n"
"out vec4 vertexColor;                 \n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);  \n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"in vec4 vertexColor;                                \n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor; \n"
"void main()\n"
"{ FragColor = vertexColor; }\n";

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	//开启面剔除
	glEnable(GL_CULL_FACE);
	//剔除背面
	glCullFace(GL_BACK);

#pragma region 第一步
	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
#pragma endregion 第一步


#pragma region 第二步
	//创建顶点着色器
	unsigned int vertexShader;
	vertexShader = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	glCompileShader(vertexShader);
	//创建偏远着色器
	unsigned int fragmentSahder;
	fragmentSahder = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragmentSahder, 1, &fragmentShaderSource, NULL);
	glCompileShader(fragmentSahder);
#pragma endregion 第二步

#pragma region 第三步
	//把这两个shader组装成一整个的着色器程序
	unsigned int shaderProgram;
	shaderProgram = glCreateProgram();
	//我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
	glAttachShader(shaderProgram, vertexShader);
	glAttachShader(shaderProgram, fragmentSahder);
	glLinkProgram(shaderProgram);
#pragma endregion 第三步

#pragma region 第四步
	//创建一个0号栏位 每三个为一组(向量),每个栏位都是一个浮点数,不需要归一化,挖完三个float再去下一个顶点
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
#pragma endregion 第四步
	//我们希望窗口可以一直画下去(展现在屏幕上)
	//while里判断是否关闭这个窗了
	while (!glfwWindowShouldClose(window))
	{
		//检测输入
		processInput(window);

		//用颜色清屏
		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);


		// 更新uniform颜色
		float timeValue = glfwGetTime();
		float greenValue = sin(timeValue) / 2.0f + 0.5f;
		int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
		glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);

		glUseProgram(shaderProgram);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

上面代码我们还修改了上次解释的EBO(这里错误我留下当做警示)真正的EBO的顺序应该是这样:

 

现在我们就拥有一个渐变颜色的多边形了(我们只在每个顶点上赋颜色,但是opengl自动帮我们渐变)

//_________________________________________//

OK现在为止一切很顺利,但是我们创建着色器是不是有点太麻烦了,现在我们来用文件流创建我们自己的shader

文件流:

1.先创建shader类

 头文件里写shder构造函数的声明,cpp里写定义(利用文件流读取我们的txt文档,并最终得到const char*类型的值(怎么样const char*是不是很眼熟!!!))

2.添加我们着色器文件(.text)并把我们之前写的着色器代码复制给他(记得去掉引号)

 Shader.h:

#pragma once
#include <string>

class Shader
{
public:
	Shader(const char* vertexPath, const char* fragmentPath);
	std:: string vertexSting;
	std::string fragmentSting;
	const char* vertexSource;
	const char* fragmentSource;

	unsigned int ID;   //Shader Program ID
	void use();
};

Shader.cpp:

#include "Shader.h"
#include <iostream>
#include <fstream>
#include <sstream>

#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>

using namespace std;
Shader::Shader(const char* vertexPath, const char* fragmentPath )
{
	
	ifstream vertexFile;
	ifstream fragmentFile;

	stringstream vertexSSteam;
	stringstream fragSSteam;

	//打开文档(注意打开文档并不算把文档放进内存顶多算和外部的文档做了个关联)
	vertexFile.open(vertexPath);
	fragmentFile.open(fragmentPath);
	//防止怀档
	vertexFile.exceptions(ifstream::failbit || ifstream::badbit);
	fragmentFile.exceptions(ifstream::failbit || ifstream::badbit);
	//判断下是否打开文档
	try
	{
		if (!vertexFile.is_open()|| !fragmentFile.is_open()) {
			throw exception("open file error");
		}
		//没有打开失败的话,就执行(红色到绿色到黄色那块)
		//关于stringstream 这里有篇文章介绍的很好 https://blog.csdn.net/liitdar/article/details/82598039

		//利用rdbuf()把打开的文件流注入到stringstream
		vertexSSteam << vertexFile.rdbuf();
		fragSSteam << fragmentFile.rdbuf();

		//使用 str() 方法,将 stringstream 类型转换为 string 类型;
		vertexSting = vertexSSteam.str();
		fragmentSting = fragSSteam.str();

		//c_str():生成一个const char*指针,指向以空字符终止的数组。
		vertexSource = vertexSting.c_str();
		fragmentSource = fragmentSting.c_str();

		unsigned int vertex, fragment;

		vertex = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex, 1, &vertexSource, NULL);
		glCompileShader(vertex);

		fragment = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragment, 1, &fragmentSource, NULL);
		glCompileShader(fragment);

		ID = glCreateProgram();
		glAttachShader(ID, vertex);
		glAttachShader(ID, fragment);
		glLinkProgram(ID);

		glDeleteShader(vertex);
		glDeleteShader(fragment);
	}
	catch (const std::exception& ex)
	{
		printf(ex.what());
	}
}

void Shader::use() {
	glUseProgram(ID);
}

main.cpp

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>

#include "Shader.h"
using namespace std;
float vertices[] = {
	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 
	 0.8f,  0.8f, 0.0f,0.3f,0.5f,0.7f
	//-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 
	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
};
unsigned int indices[] = { // 注意索引从0开始! 
	2, 1, 0, // 第一个三角形
	3, 2, 0  // 第二个三角形
	//0,1,2,
	//2,3,1
};

const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;   \n"
"out vec4 vertexColor;                 \n"
"void main()\n"
"{\n"
"   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);  \n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"in vec4 vertexColor;                                \n"
"out vec4 FragColor;\n"
"uniform vec4 ourColor; \n"
"void main()\n"
"{ FragColor = vertexColor; }\n";

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个0号栏位 每三个为一组(向量),每个栏位都是一个浮点数,不需要归一化,挖完三个float再去下一个顶点
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);

	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);


	创建顶点着色器
	//unsigned int vertexShader;
	//vertexShader = glCreateShader(GL_VERTEX_SHADER);
	//glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
	//glCompileShader(vertexShader);
	创建偏远着色器
	//unsigned int fragmentSahder;
	//fragmentSahder = glCreateShader(GL_FRAGMENT_SHADER);
	//glShaderSource(fragmentSahder, 1, &fragmentShaderSource, NULL);
	//glCompileShader(fragmentSahder);

	把这两个shader组装成一整个的着色器程序
	//unsigned int shaderProgram;
	//shaderProgram = glCreateProgram();
	我们需要把之前编译的着色器附加到程序对象上,然后用glLinkProgram链接它们:
	//glAttachShader(shaderProgram, vertexShader);
	//glAttachShader(shaderProgram, fragmentSahder);
	//glLinkProgram(shaderProgram);


	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);


		 更新uniform颜色
		//float timeValue = glfwGetTime();
		//float greenValue = sin(timeValue) / 2.0f + 0.5f;
		//int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
		//glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
		//glUseProgram(shaderProgram);

		testShader->use();

		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

fragmentSource.txt:

#version 330 core
in vec4 vertexColor;                                
out vec4 FragColor;
void main()
{
    FragColor = vertexColor;
}

 vertexSource.txt:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;   
out vec4 vertexColor;                 
void main()
{
   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);  
}

 现在我们拥有自己的shader类,规范化的同时又简化不少步骤 可喜可贺(不过需要注意声明shader的位置,这里我放在了glViewport后)

但我们还可以再苛刻一点,我们的着色器没有报错信息,确实很令人苦恼,现在我们来解决这件事

四、纹理贴图

现在我们已经可以给每个顶点附上颜色达到一个比较好的效果,但如果我们想要更真实的图像该怎么办?

添加更多的顶点?这也算是个办法,但会增加许多没必要的开销,我们可以把一张纹理映射到我们的图形上(每个顶点都有一个纹理坐标,用来标明采样纹理图像的哪个部分))

首先我们来加载图像文件:

先利用添加现有项,在项目里放入我们的image

(说起来JPG是没有Alpha通道的,png有)

 然后我们放入读取image的头文件(直接复制然后新建头文件,或者外部创建.h文件 然后到处现有项就好)

现在我们做个测试看看是否引用成功

#include <iostream>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

using namespace std;

int main() {
	int width, height, nrChannels;
	//opnegl里面x轴是反的 这里反过来
	stbi_set_flip_vertically_on_load(true);
	unsigned char *data = stbi_load("myImage0000.png", &width, &height, &nrChannels, 0);
	for (size_t i = 0; i < 50; i++)
	{
		cout << (int)data[i] << endl;
	}
	//释放内存是个好习惯
	stbi_image_free(data);
	while (true)
	{

	}
	return 0;
}

我们先来看一看纹理环绕方式:

纹理坐标是0到1 但我们有个1.5的数值该怎么办?

我们有以下几个办法:

GL_REPEAT(无限重复)

GL_CLAMP_TO_EDGE(取边缘颜色)

...

对应unity里的

 我们再来看看纹理过滤

GL_NEAREST(也叫邻近过滤)

GL_LINEAR(也叫线性过滤)

...

对应unity里的

多级渐远纹理(mipmap)

GL_NEAREST_MIPMAP_NEAREST

...

unity里会自动帮我们产生

提一下unity里还有各向异性过滤(远处的材质的清晰度)

现在我们删掉Test,来做这个: 把图形的坐标映射到uv的坐标(0-1)中去

 注意!!注意!!千万别用(或者说尽量)长方形的图片!!!要用正方形的图片,或者2的n次方幂

OK,现在我们正式开始

先修改我们的数据,还是只用一个VBO,但是这里面除了顶点位置,顶点颜色,现在再加上纹理坐标

(虽然足够底层,但是连纹理坐标都要自己来搞,确实有点不习惯---小声逼逼)

搞个栏位

 输入下纹理坐标到顶点着色器

 片元着色器利用uniform从外部获取到纹理 然后用顶点着色器传来的纹理坐标采样(opengl会自己插值)

到目前为止,我们的顶点坐标已经可以传入到我们的着色器里面了,并且还在片面着色器里设置了个uniform(也就是说从CPU里面传入GPU)用来获取图片数据

获取图片数据我是这么理解的(先创建个BUFF,把buff和VAO连接,然后把数据放到buff中)

OK现在我们来实现

创建buff

 然后就是灌入图片数据

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
using namespace std;
float vertices[] = {
	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
	//-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 
	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};



void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	//创建一个栏位放顶点颜色
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBuffer;
	glGenTextures(1, &TexBuffer);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBuffer);

	//加载图片
	int width, height, nrChannel;
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);
	

	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glBindTexture(GL_TEXTURE_2D, TexBuffer);

		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		


		testShader->use();

		
		
		

		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

 当然你也可以在片元着色器乘上一个颜色,让我们的贴图更多彩一点

#version 330 core
out vec4 FragColor;

in vec2 TexCoord;
in vec4 vertexColor;
uniform sampler2D ourTexture;

void main()
{
    FragColor = texture(ourTexture, TexCoord)*vertexColor;
}

 现在我们还不满足,想要两张贴图一起显示的效果(类似于正片叠底)

思路是再开一个Buff 把两张图都读取进来

意思是先再创建一个槽位,并传入数据

并且自己来移动下槽位 让他不要在0号位

OK 具体代码奉上:

#version 330 core
out vec4 FragColor;

in vec2 TexCoord;
in vec4 vertexColor;
uniform sampler2D ourTexture;
uniform sampler2D ourFace;

void main()
{
    FragColor = texture(ourTexture, TexCoord)*texture(ourFace, TexCoord);
}

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
using namespace std;
float vertices[] = {
	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
	//-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 
	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};



void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	//创建一个栏位放顶点颜色
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBufferA;
	glGenTextures(1, &TexBufferA);
	glActiveTexture(GL_TEXTURE0);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	//加载图片
	int width, height, nrChannel;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);
	

	//创建个Tex Buffer
	unsigned int TexBufferB;
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE1);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	//加载图片
	int width2, height2, nrChannel2;
	
	unsigned char* data2 = stbi_load("awesomeface.png", &width2, &height2, &nrChannel2, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data2) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data2);

	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, TexBufferB);



		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		


		testShader->use();
		glUniform1i(glGetUniformLocation(testShader->ID, "ourTexture"), 0);
		glUniform1i(glGetUniformLocation(testShader->ID, "ourFace"), 1);
		
		
		

		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

五、变换

到现在为止,我们的物体还是静态的,现在我们让他们动起来

在这之前我们需要了解点知识(这里不再赘述)

记得下载和配置GLM

尝试运用一下

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>

int main() {

	//创建一个向量
	glm::vec4 vec(1.0f, 0.0f, 0.0f, 1.0f);
	//创建一个矩阵(单位矩阵4*4)
	glm::mat4 trans;

	//进行位移操作
	trans = glm::translate(trans, glm::vec3(2.0f, 0.0f, 0.0f));

	vec = trans * vec;

	std::cout << vec.x << vec.y << vec.z << std::endl;
}

多个变换有顺序

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
float vertices[] = {
	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
	//-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 
	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};



void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	//创建一个栏位放顶点颜色
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBufferA;
	glGenTextures(1, &TexBufferA);
	glActiveTexture(GL_TEXTURE0);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	//加载图片
	int width, height, nrChannel;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);
	

	//创建个Tex Buffer
	unsigned int TexBufferB;
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE1);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	//加载图片
	int width2, height2, nrChannel2;
	
	unsigned char* data2 = stbi_load("awesomeface.png", &width2, &height2, &nrChannel2, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data2) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data2);

	glm::mat4 trans;
	trans = glm::translate(trans, glm::vec3(0.5f, -0.5f, 0.0f));
	


	/*trans = glm::rotate(trans, glm::radians(90.0f), glm::vec3(0, 0, 1.0f));
	trans = glm::scale(trans, glm::vec3(0.5f, 0.5f, 0.5f));*/

	while (!glfwWindowShouldClose(window))
	{
		trans = glm::rotate(trans, (float)glfwGetTime(), glm::vec3(0.0f, 0.0f, 1.0f));
		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, TexBufferB);



		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		


		testShader->use();
		glUniform1i(glGetUniformLocation(testShader->ID, "ourTexture"), 0);
		glUniform1i(glGetUniformLocation(testShader->ID, "ourFace"), 1);
		unsigned int transformLoc = glGetUniformLocation(testShader->ID, "transform");
		glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(trans));
		
		

		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

 #version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;   
out vec4 vertexColor;                 
out vec2 TexCoord;
uniform mat4 transform;
void main()
{
   gl_Position = transform*vec4(aPos.x, aPos.y, aPos.z, 1.0);
    vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);  
    TexCoord = aTexCoord;
}

 六、坐标系统

 1.我们先来尝试把一个3D的平面,静止在一个虚构的地板上

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;   
out vec4 vertexColor;                 
out vec2 TexCoord;
uniform mat4 transform;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
   gl_Position =  projection * view * model *vec4(aPos.x, aPos.y, aPos.z, 1.0);
    vertexColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);  
    TexCoord = aTexCoord;
}

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
float vertices[] = {
	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
	//-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 
	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
};
unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};



void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	//创建一个栏位放顶点颜色
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBufferA;
	glGenTextures(1, &TexBufferA);
	glActiveTexture(GL_TEXTURE0);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	//加载图片
	int width, height, nrChannel;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);
	

	//创建个Tex Buffer
	unsigned int TexBufferB;
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE1);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	//加载图片
	int width2, height2, nrChannel2;
	
	unsigned char* data2 = stbi_load("awesomeface.png", &width2, &height2, &nrChannel2, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data2) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data2);

	glm::mat4 model;
	model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));

	glm::mat4 view;
	view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

	glm::mat4 projection;
	projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);

	while (!glfwWindowShouldClose(window))
	{
		
		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, TexBufferB);



		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		


		testShader->use();
		glUniform1i(glGetUniformLocation(testShader->ID, "ourTexture"), 0);
		glUniform1i(glGetUniformLocation(testShader->ID, "ourFace"), 1);


		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
		
		

		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

现在我们已经把我们的平面放到我们的坐标系上去了

但我们还不满足,想要一个完整的立方体 现在我们来实现

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "std_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
//float vertices[] = {
//	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
//	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
//	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
//	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
//	//-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 
//	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
//};


float vertices[] = {
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};


unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};



void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	开启面剔除
	//glEnable(GL_CULL_FACE);
	剔除背面
	//glCullFace(GL_BACK);

	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	创建一个栏位放顶点颜色
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	//glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBufferA;
	glGenTextures(1, &TexBufferA);
	glActiveTexture(GL_TEXTURE0);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	//加载图片
	int width, height, nrChannel;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);


	//创建个Tex Buffer
	unsigned int TexBufferB;
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE1);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	//加载图片
	int width2, height2, nrChannel2;

	unsigned char* data2 = stbi_load("awesomeface.png", &width2, &height2, &nrChannel2, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data2) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data2);

	glm::mat4 model;
	model = glm::rotate(model, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));

	glm::mat4 view;
	view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

	glm::mat4 projection;
	projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);

	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, TexBufferB);



		glBindVertexArray(VAO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);



		testShader->use();
		glUniform1i(glGetUniformLocation(testShader->ID, "ourTexture"), 0);
		glUniform1i(glGetUniformLocation(testShader->ID, "ourFace"), 1);


		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));


		glDrawArrays(GL_TRIANGLES, 0, 36);
		//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

开启下Z缓冲

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "std_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std;
//float vertices[] = {
//	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
//	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
//	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
//	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
//	//-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 
//	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
//};


float vertices[] = {
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};


unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};

glm::vec3 cubePositions[] = {
  glm::vec3(0.0f,  0.0f,  0.0f),
  glm::vec3(2.0f,  5.0f, -15.0f),
  glm::vec3(-1.5f, -2.2f, -2.5f),
  glm::vec3(-3.8f, -2.0f, -12.3f),
  glm::vec3(2.4f, -0.4f, -3.5f),
  glm::vec3(-1.7f,  3.0f, -7.5f),
  glm::vec3(1.3f, -2.0f, -2.5f),
  glm::vec3(1.5f,  2.0f, -2.5f),
  glm::vec3(1.5f,  0.2f, -1.5f),
  glm::vec3(-1.3f,  1.0f, -1.5f)
};

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	//开启面剔除
	/*glEnable(GL_CULL_FACE);*/
	剔除背面
	//glCullFace(GL_BACK);
	glEnable(GL_DEPTH_TEST);


	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	创建一个栏位放顶点颜色
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	//glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBufferA;
	glGenTextures(1, &TexBufferA);
	glActiveTexture(GL_TEXTURE0);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	//加载图片
	int width, height, nrChannel;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);


	//创建个Tex Buffer
	unsigned int TexBufferB;
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE1);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	//加载图片
	int width2, height2, nrChannel2;

	unsigned char* data2 = stbi_load("awesomeface.png", &width2, &height2, &nrChannel2, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data2) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data2);

	glm::mat4 model;
	model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(0.0f, 1.0f, 1.0f));

	glm::mat4 view;
	view = glm::translate(view, glm::vec3(0.0f, 0.0f, -3.0f));

	glm::mat4 projection;
	projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);

	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, TexBufferB);



		glBindVertexArray(VAO);
		/*glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);*/

		for (unsigned int i = 0; i < 10; i++)
		{
			glm::mat4 model;
			model = glm::translate(model, cubePositions[i]);
		testShader->use();
		glUniform1i(glGetUniformLocation(testShader->ID, "ourTexture"), 0);
		glUniform1i(glGetUniformLocation(testShader->ID, "ourFace"), 1);


		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));


		glDrawArrays(GL_TRIANGLES, 0, 36);

		}

		//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

七、摄像机

camer类

#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
//#ifndef  CAMERA_H
//#define CAMERA_H
class Camer
{
public:
    Camer(glm::vec3 postion, glm::vec3 target, glm::vec3 worldup);
    Camer(glm::vec3 postion, float pitch, float yaw, glm::vec3 worldUp);
    ~Camer();
    glm::vec3 Position;
    glm::vec3 Forward;
    glm::vec3 Right;
    glm::vec3 Up;
    glm::vec3 WorldUp;

    glm::mat4 GetViewMatrix();
};
//#endif // ! CAMERA_H

#include "Camer.h"
Camer::Camer(glm::vec3 postion, glm::vec3 target, glm::vec3 worldup) {
    Position = postion;
    WorldUp = worldup;
    Forward = glm::normalize(target - postion);
    Right = glm::normalize(glm::cross(Forward, WorldUp));
    Up = glm::normalize(glm::cross(Forward, Right));
}
Camer::Camer(glm::vec3 postion, float pitch, float yaw, glm::vec3 worldUp)
{
    Position = postion;
    WorldUp = worldUp;
    Forward.x = glm::cos(pitch) * glm::sin(yaw);
    Forward.y = glm::sin(pitch);
    Forward.z = glm::cos(pitch) * glm::cos(yaw);
    Right = glm::normalize(glm::cross(Forward, WorldUp));
    Up = glm::normalize(glm::cross(Forward, Right));
}
Camer::~Camer() {

}

glm::mat4 Camer::GetViewMatrix()
{
    return glm::lookAt(Position, Position + Forward, WorldUp);
}

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Camer.h";
using namespace std;
//float vertices[] = {
//	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
//	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
//	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
//	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
//	//-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 
//	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
//};


float vertices[] = {
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};


unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};

glm::vec3 cubePositions[] = {
  glm::vec3(0.0f,  0.0f,  0.0f),
  glm::vec3(2.0f,  5.0f, -15.0f),
  glm::vec3(-1.5f, -2.2f, -2.5f),
  glm::vec3(-3.8f, -2.0f, -12.3f),
  glm::vec3(2.4f, -0.4f, -3.5f),
  glm::vec3(-1.7f,  3.0f, -7.5f),
  glm::vec3(1.3f, -2.0f, -2.5f),
  glm::vec3(1.5f,  2.0f, -2.5f),
  glm::vec3(1.5f,  0.2f, -1.5f),
  glm::vec3(-1.3f,  1.0f, -1.5f)
};

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}
}
int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	//开启面剔除
	/*glEnable(GL_CULL_FACE);*/
	剔除背面
	//glCullFace(GL_BACK);
	glEnable(GL_DEPTH_TEST);


	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	创建一个栏位放顶点颜色
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	//glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBufferA;
	glGenTextures(1, &TexBufferA);
	glActiveTexture(GL_TEXTURE0);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	//加载图片
	int width, height, nrChannel;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);


	//创建个Tex Buffer
	unsigned int TexBufferB;
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE1);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	//加载图片
	int width2, height2, nrChannel2;

	unsigned char* data2 = stbi_load("awesomeface.png", &width2, &height2, &nrChannel2, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data2) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data2);

	Camer camera(glm::vec3(0, 0, 3.0f), glm::vec3(0, 1.0f, 0), glm::vec3(0, 1.0f, 1.0f));

	glm::mat4 model;
	model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(0.0f, 1.0f, 1.0f));

	glm::mat4 view;
	/*view = glm::translate(view, glm::vec3(0.0f, 0.0f, -6.0f));*/
	view = camera.GetViewMatrix();

	glm::mat4 projection;
	projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);

	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, TexBufferB);



		glBindVertexArray(VAO);
		/*glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);*/

		for (unsigned int i = 0; i < 10; i++)
		{
			glm::mat4 model;
			model = glm::translate(model, cubePositions[i]);
			float angle = 20.0f * i;
			model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
			testShader->use();
			glUniform1i(glGetUniformLocation(testShader->ID, "ourTexture"), 0);
			glUniform1i(glGetUniformLocation(testShader->ID, "ourFace"), 1);


			glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
			glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
			glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));


			glDrawArrays(GL_TRIANGLES, 0, 36);

		}

		//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();


	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

欧拉角版本:

最后了 让摄像机动起来

#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
//#ifndef  CAMERA_H
//#define CAMERA_H
class Camer
{
public:
    Camer(glm::vec3 postion, glm::vec3 target, glm::vec3 worldup);
    Camer(glm::vec3 postion, float pitch, float yaw, glm::vec3 worldUp);
    ~Camer();
    glm::vec3 Position;
    glm::vec3 Forward;
    glm::vec3 Right;
    glm::vec3 Up;
    glm::vec3 WorldUp;
    float Pitch;
    float Yaw;
    float speedZ = 0;
    glm::mat4 GetViewMatrix();
    void ProcessMouseMovement(float deltaX, float deltaY);
    void UpdateCameraPos();
private:
    void UpdateCameraVectors();
};
//#endif // ! CAMERA_H

#include "Camer.h"
Camer::Camer(glm::vec3 postion, glm::vec3 target, glm::vec3 worldup) {
    Position = postion;
    WorldUp = worldup;
    Forward = glm::normalize(target - postion);
    Right = glm::normalize(glm::cross(Forward, WorldUp));
    Up = glm::normalize(glm::cross(Forward, Right));
}
Camer::Camer(glm::vec3 postion, float pitch, float yaw, glm::vec3 worldUp)
{
    Position = postion;
    WorldUp = worldUp;
    Pitch = pitch;
    Yaw = yaw;
    Forward.x = glm::cos(Pitch) * glm::sin(Yaw);
    Forward.y = glm::sin(Pitch);
    Forward.z = glm::cos(Pitch) * glm::cos(Yaw);
    Right = glm::normalize(glm::cross(Forward, WorldUp));
    Up = glm::normalize(glm::cross(Forward, Right));
}
Camer::~Camer() {

}

glm::mat4 Camer::GetViewMatrix()
{
    return glm::lookAt(Position, Position + Forward, WorldUp);
}

void Camer::ProcessMouseMovement(float deltaX, float deltaY)
{
    Pitch -= deltaY*0.01f;
    Yaw -= deltaX*0.01f;
    UpdateCameraVectors();
}

void Camer::UpdateCameraVectors()
{
    Forward.x = glm::cos(Pitch) * glm::sin(Yaw);
    Forward.y = glm::sin(Pitch);
    Forward.z = glm::cos(Pitch) * glm::cos(Yaw);
    Right = glm::normalize(glm::cross(Forward, WorldUp));
    Up = glm::normalize(glm::cross(Forward, Right));
}

void Camer::UpdateCameraPos()
{
    Position += glm::vec3(0, 0, speedZ*0.01f);
}

#include<iostream>
#define GLEW_STATIC
#include <GL/glew.h>
#include<GLFW\glfw3.h>
#include "Shader.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include "Camer.h";
using namespace std;
//float vertices[] = {
//	 0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f,   // 右上
//	 0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f,   // 右下
//	-0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f,   // 左下
//	-0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f
//	//-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 
//	// 0.8f,  0.8f, 0.0f, 0.3f,0.5f,0.7f
//};


float vertices[] = {
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
	 0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	 0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
	-0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
	-0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};


unsigned int indices[] = { // 注意索引从0开始! 
	0,1,2, // 第一个三角形
	2,3,0  // 第二个三角形
	//0,1,2,
	//2,3,1
};

glm::vec3 cubePositions[] = {
  glm::vec3(0.0f,  0.0f,  0.0f),
  glm::vec3(2.0f,  5.0f, -15.0f),
  glm::vec3(-1.5f, -2.2f, -2.5f),
  glm::vec3(-3.8f, -2.0f, -12.3f),
  glm::vec3(2.4f, -0.4f, -3.5f),
  glm::vec3(-1.7f,  3.0f, -7.5f),
  glm::vec3(1.3f, -2.0f, -2.5f),
  glm::vec3(1.5f,  2.0f, -2.5f),
  glm::vec3(1.5f,  0.2f, -1.5f),
  glm::vec3(-1.3f,  1.0f, -1.5f)
};

float lastX,lastY;
bool firstMouse = true;
/*Camer camera(glm::vec3(0, 0, 3.0f), glm::vec3(0, 1.0f, 0), glm::vec3(0, 1.0f, 1.0f));*/
Camer camera(glm::vec3(0, 0, 3.0f), glm::radians(15.0f), glm::radians(180.0f), glm::vec3(0, 1.0f, 0));

void processInput(GLFWwindow* window) {
	//检测是否按下ESC
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		//关闭窗口
		glfwSetWindowShouldClose(window, true);
	}

	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
		//前进
		camera.speedZ=1.0f;
	}
	else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
		//后退
		camera.speedZ=-1.0f;
	}
	else
	{
		camera.speedZ=0;
	}
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
	//防止第一次进入的时候爆很大的值
	if (firstMouse == true) {
		lastX = xpos;
		lastY = ypos;
		firstMouse = false;
	}

	float deltaX, deltaY;
	//计算差值
	deltaX = xpos - lastX;
	deltaY = ypos - lastY;

	lastX = xpos;
	lastY = ypos;

	camera.ProcessMouseMovement(deltaX, deltaY);
}

int main()
{

	glfwInit();//初始化
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//配置GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);//配置GLFW
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//开窗
	GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", nullptr, nullptr);
	//判断是否开窗失败
	if (window == nullptr)
	{
		cout << "Failed to create GLFW window" << endl;
		//终止掉的函数
		glfwTerminate();
		return -1;
	}
	//把我们创建的window当做主要的上下文(就是要用这个window的意思)
	glfwMakeContextCurrent(window);
	//我们要告诉GLFW,它应该隐藏光标,并捕捉(Capture)它
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

	glfwSetCursorPosCallback(window, mouse_callback);

	//解锁glew(?)
	glewExperimental = true;
	//判断glew底下操作是否成功
	if (glewInit() != GLEW_OK) {
		printf("init glew failed");
		glfwTerminate();
		return -1;
	}

	//第三第四个参数可以设置渲染的像素值
	glViewport(0, 0, 800, 600);
	//开启面剔除
	/*glEnable(GL_CULL_FACE);*/
	剔除背面
	//glCullFace(GL_BACK);
	glEnable(GL_DEPTH_TEST);


	Shader* testShader = new Shader("vertexSource.txt", "fragmentSource.txt");



	//定义一个VAO
	unsigned int VAO;
	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	//定义一个VBO
	unsigned int VBO;
	glGenBuffers(1, &VBO);
	//把VBO绑在VAO里的ABUFFER
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	//专门用来把用户定义的数据复制到当前绑定缓冲的函数
	//刚才绑定了ABUFFER的内存 现在把数据放到这里面
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	unsigned int EBO;
	glGenBuffers(1, &EBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


	//创建一个栏位放顶点位置
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
	glEnableVertexAttribArray(0);
	创建一个栏位放顶点颜色
	//glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
	//glEnableVertexAttribArray(1);
	//创建一个栏位放纹理坐标
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
	glEnableVertexAttribArray(2);


	//创建个Tex Buffer
	unsigned int TexBufferA;
	glGenTextures(1, &TexBufferA);
	glActiveTexture(GL_TEXTURE0);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferA);
	//加载图片
	int width, height, nrChannel;
	stbi_set_flip_vertically_on_load(true);
	unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannel, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data);


	//创建个Tex Buffer
	unsigned int TexBufferB;
	glGenTextures(1, &TexBufferB);
	glActiveTexture(GL_TEXTURE1);
	//通过某个神秘通道绑上VAO
	glBindTexture(GL_TEXTURE_2D, TexBufferB);
	//加载图片
	int width2, height2, nrChannel2;

	unsigned char* data2 = stbi_load("awesomeface.png", &width2, &height2, &nrChannel2, 0);
	//判断下data是否为空,不为空我们就可以通过刚才绑定的通道灌东西进去了
	if (data2) {
		//输入数据到buff
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width2, height2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);
		//设置环绕方式和过滤方式可以不用写用默认值,但mipmap不写会直接不显示
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		cout << "Load image failed" << endl;
	}
	//释放内存
	stbi_image_free(data2);

	glm::mat4 model;
	model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(0.0f, 1.0f, 1.0f));

	glm::mat4 view;
	/*view = glm::translate(view, glm::vec3(0.0f, 0.0f, -6.0f));*/
	/*view = camera.GetViewMatrix();*/

	glm::mat4 projection;
	projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);

	while (!glfwWindowShouldClose(window))
	{

		processInput(window);

		glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, TexBufferA);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, TexBufferB);



		glBindVertexArray(VAO);
		/*glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);*/

		view = camera.GetViewMatrix();

		for (unsigned int i = 0; i < 10; i++)
		{
			glm::mat4 model;
			model = glm::translate(model, cubePositions[i]);
			float angle = 20.0f * i;
			model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
			testShader->use();
			glUniform1i(glGetUniformLocation(testShader->ID, "ourTexture"), 0);
			glUniform1i(glGetUniformLocation(testShader->ID, "ourFace"), 1);


			glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "model"), 1, GL_FALSE, glm::value_ptr(model));
			glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "view"), 1, GL_FALSE, glm::value_ptr(view));
			glUniformMatrix4fv(glGetUniformLocation(testShader->ID, "projection"), 1, GL_FALSE, glm::value_ptr(projection));


			glDrawArrays(GL_TRIANGLES, 0, 36);

		}

		//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);



		//双缓冲 两个缓冲的会切换 前缓冲负责显示 后缓冲负责绘制
		glfwSwapBuffers(window);
		//获取用户按得按键(?)
		glfwPollEvents();

		camera.UpdateCameraPos();
	}
	//清楚我们配置的资源
	glfwTerminate();
	return 0;


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值