OpenGL之——3D漫游(金字塔)

简易版3D漫游金字塔效果如下:

OpenGL之——3D漫游(金字塔)_第1张图片

 面重合部分的纹理争夺战:

OpenGL之——3D漫游(金字塔)_第2张图片

 代码:

main.cpp


#include 
#include 
#include 
#define STB_IMAGE_IMPLEMENTATION
#include 
#include "Shader.h"

#include 
#include 
#include 

#pragma comment(lib,"glfw3.lib")

using namespace std;

//摄像机
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);

GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;


void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);


void processInput(GLFWwindow* window);

GLuint Width = 800, Height = 600;

bool firstMouse = true;
float yaw = -90.0f;	// yaw is initialized to -90.0 degrees since a yaw of 0.0 results in a direction vector pointing to the right so we initially rotate a bit to the left.
float pitch = 0.0f;
float lastX = 800.0f / 2.0;
float lastY = 600.0f / 2.0;
float fov = 45.0f;

int main() {
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	
	GLFWwindow* window = glfwCreateWindow(Width, Height, "LearnOpenGL", NULL, NULL);

	if (window == NULL) {
		cout << "Failed to create GLFW window" << endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//注册回调函数
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetScrollCallback(window, scroll_callback);

	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
		cout << "Failed to initialize GLAD" << endl;
		return -1;
	}

	
	
	//创建顶点缓存对象用来管理分配到的顶点缓存空间
	//创建一个着色器对象
	
	Shader ShaderColor("shader.vs","shader.frag");
	

	glEnable(GL_DEPTH_TEST);

	GLfloat vertices[] = {
		// 第一个三角形     texture
		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, 0.0f, 1.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, 0.0f, // 左下角
		  0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		0.5f, -0.5f,  0.5f, 1.0f, 0.0f,  // 右下角
		//第四个三角形
		0.5f, -0.5f,  0.5f, 0.0f, 0.0f,  // 右下角
		0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		0.5f, -0.5f, -0.5f,  1.0f, 0.0f,  // 右上角
		//第五个三角形
		0.5f, -0.5f, -0.5f,  0.0f, 0.0f,  // 右上角
		0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		-0.5f,-0.5f, -0.5f, 1.0f, 0.0f, // 左上角
		//第六个三角形
		-0.5f,-0.5f, -0.5f, 0.0f, 0.0f,  // 左上角
		0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		-0.5f, -0.5f, 0.5f, 1.0f, 0.0f  // 左下角
	}; 
	glm::vec3 cubePositions[] = {
		  glm::vec3(0.0f,  0.0f,  0.0f),
		  glm::vec3(1.0f,  1.0f, 0.0f),
		  glm::vec3(-1.5f, -2.2f, -2.5f),
		  glm::vec3(-3.8f, -2.0f, -3.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)
	};
	
	GLuint VAO, VBO;
	glGenVertexArrays(1, &VAO);//创建顶点数组对象
	glGenBuffers(1, &VBO);//创建顶点缓冲对象

	glBindBuffer(GL_ARRAY_BUFFER, VBO);//将顶点缓冲绑定到顶点缓冲对象
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//缓冲区三角形顶点数据



	glBindVertexArray(VAO);//将顶点数组绑定到顶点数组对象
	//设置顶点属性指针
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 );
	glEnableVertexAttribArray(1);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);

	//纹理
	GLuint texture[3];
	glGenTextures(3, texture);
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	//为当前绑定的对象设置环绕,过滤方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//加载并生成纹理一
	int width, height, nrChannels;
	stbi_set_flip_vertically_on_load(true);//在图像加载时帮助我们翻转y轴,只需要在加载任何图像前加入以下语句即可
	unsigned char *image1 = stbi_load("box2.png", &width, &height, &nrChannels, 0);
	cout << "Channels = " << nrChannels << endl;
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	if (image1) {
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		std::cout << "Failed to load texture1" << std::endl;
	}
	stbi_image_free(image1);
	glBindTexture(GL_TEXTURE_2D, 0);
	//加载并生成纹理二
	unsigned char *image2 = stbi_load("box.jpg", &width, &height, &nrChannels, 0);
	cout << "Channels = " << nrChannels << endl;
	glBindTexture(GL_TEXTURE_2D, texture[1]);
	if (image2) {
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image2);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		std::cout << "Failed to load texture2" << std::endl;
	}
	stbi_image_free(image2);
	glBindTexture(GL_TEXTURE_2D, 0);
	//加载并生成纹理三
	unsigned char *image3 = stbi_load("face.png", &width, &height, &nrChannels, 0);
	cout << "Channels = " << nrChannels << endl;
	glBindTexture(GL_TEXTURE_2D, texture[2]);
	if (image3) {
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image3);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		std::cout << "Failed to load texture3" << std::endl;
	}
	stbi_image_free(image3);
	glBindTexture(GL_TEXTURE_2D, 0);

	//int flagLoc = glGetUniformLocation(ShaderColor.ID, "flag");//此处不再需要获取地址了
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	ShaderColor.use();
	ShaderColor.setInt("ourTexture0", 0);//设置采样器ourTexture0属于0号纹理单元
	ShaderColor.setInt("ourTexture1", 1);//设置采样器ourTexture1属于1号纹理单元
	ShaderColor.setInt("ourTexture2", 2);//设置采样器ourTexture2属于2号纹理单元

	



	while (!glfwWindowShouldClose(window)) {

		GLfloat currentFrame = glfwGetTime();
		deltaTime = currentFrame - lastFrame;//当前帧与上一帧的时间差
		lastFrame = currentFrame;//上一帧的时间

		processInput(window);

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

		ShaderColor.use();

		//变换矩阵
		glm::mat4 model = glm::mat4(1.0f);
		glm::mat4 view = glm::mat4(1.0f);
		glm::mat4 projection = glm::mat4(1.0f);
		GLuint modelLoc = glGetUniformLocation(ShaderColor.ID, "model");
		GLuint viewLoc = glGetUniformLocation(ShaderColor.ID, "view");
		GLuint projectionLoc = glGetUniformLocation(ShaderColor.ID, "projection");
		//model = glm::rotate(model, (float)-glfwGetTime()*60.0f, glm::vec3(1.0f, 0.0f, 0.0f));
		//view = glm::translate(view, glm::vec3(0.0f, 0.0f, -1.5f));
		projection = glm::perspective(glm::radians(fov), (GLfloat)Width / Height, 0.1f, 100.0f);

		
		view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);



		glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));

		glBindVertexArray(VAO);//绑定顶点数组
		for (GLuint i = 0; i < 10; i++) {
			model = glm::translate(model, cubePositions[i]);
			model = glm::rotate(model, (float)i*10.0f, glm::vec3(0.0, 1.0, 0.0));
			glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));

			ShaderColor.setInt("flag", 1);
			glActiveTexture(GL_TEXTURE1);//激活0号纹理
			glBindTexture(GL_TEXTURE_2D, texture[1]);//绑定1号纹理为texture[1]
			glActiveTexture(GL_TEXTURE2);//激活1号纹理
			glBindTexture(GL_TEXTURE_2D, texture[2]);//绑定2号纹理为texture[2]
			glDrawArrays(GL_TRIANGLES, 0, 3);//右上三角形


			ShaderColor.setInt("flag", 2);
			glActiveTexture(GL_TEXTURE0);//激活0号纹理
			glBindTexture(GL_TEXTURE_2D, texture[0]);//绑定0号纹理为texture[0]
			glDrawArrays(GL_TRIANGLES, 3, 3);//左下三角形

			ShaderColor.setInt("flag", 3);
			glActiveTexture(GL_TEXTURE0);//激活0号纹理
			glBindTexture(GL_TEXTURE_2D, texture[0]);//绑定0号纹理为texture[0]
			glDrawArrays(GL_TRIANGLES, 6, 12);//左下三角形
		}
		

		glBindVertexArray(0);//解绑顶点数组
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glDeleteBuffers(1, &VBO);
	glDeleteVertexArrays(1, &VAO);
	glfwTerminate();
	return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
	glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);

	float cameraSpeed = 5.5 * deltaTime;
	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
		cameraPos += cameraSpeed * cameraFront;
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
		cameraPos -= cameraSpeed * cameraFront;
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
		cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
		cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
	if (firstMouse)
	{
		lastX = xpos;
		lastY = ypos;
		firstMouse = false;
	}

	float xoffset = xpos - lastX;
	float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
	lastX = xpos;
	lastY = ypos;

	float sensitivity = 0.1f; // change this value to your liking
	xoffset *= sensitivity;
	yoffset *= sensitivity;

	yaw += xoffset;
	pitch += yoffset;

	// make sure that when pitch is out of bounds, screen doesn't get flipped
	if (pitch > 89.0f)
		pitch = 89.0f;
	if (pitch < -89.0f)
		pitch = -89.0f;

	glm::vec3 front;
	front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
	front.y = sin(glm::radians(pitch));
	front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
	cameraFront = glm::normalize(front);
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
	if (fov > 1.0f && fov <= 45.0f)
		fov -= yoffset;
	if (fov <= 1.0f)
		fov = 1.0f;
	if (fov >= 45.0f)
		fov = 45.0f;
}
#pragma once

#include 
#include 
#include 
#include 
#include 

class Shader {
public:
	GLuint ID;//程序ID

	//构造器读取并构建着色器
	Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
	//使用、激活程序
	void use();
	//uniform工具函数
	void setBool(const std::string &name, bool value) const;
	void setInt(const std::string &name, int value) const;
	void setFloat(const std::string &name, float value) const;
};



Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath) {
	//从文件路径中获取顶点、片段着色器
	std::string vertexCode;//用来存储顶点着色器的字符串形式
	std::string fragmentCode;//用来存储片段着色器的字符串形式
	std::ifstream vShaderFile;//以输入方式打开
	std::ifstream fShaderFile;//以输入方式打开
	//保证ifstream对象可以抛出异常
	vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	try {
		//打开文件
		vShaderFile.open(vertexPath);//以输入方式打开
		fShaderFile.open(fragmentPath);
		std::stringstream vShaderStream, fShaderStream;
		//读取文件的缓冲内容到数据流中
		vShaderStream << vShaderFile.rdbuf();
		fShaderStream << fShaderFile.rdbuf();
		//关闭文件处理器
		vShaderFile.close();
		fShaderFile.close();
		//转换数据流到string
		vertexCode = vShaderStream.str();//字符串流转换成字符串
		fragmentCode = fShaderStream.str();
	}
	catch (std::ifstream::failure e) {
		std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
	}
	const GLchar* vShaderCode = vertexCode.c_str();
	const GLchar* fShaderCode = fragmentCode.c_str();

	//编译着色器
	GLuint vertex, fragment;
	GLint success;
	GLchar infoLog[512];
	//VertexShader
	vertex = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex, 1, &vShaderCode, NULL);
	glCompileShader(vertex);

	glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(vertex, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
	}

	//fragmentShader
	fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &fShaderCode, NULL);
	glCompileShader(fragment);

	glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragment, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
	}

	//ShaderProgram
	this->ID = glCreateProgram();//产生着色器程序ID
	glAttachShader(this->ID, vertex);
	glAttachShader(this->ID, fragment);
	glLinkProgram(this->ID);

	glGetProgramiv(this->ID, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(this->ID, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED...\n" << infoLog << std::endl;
	}
	glDeleteShader(vertex);
	glDeleteShader(fragment);
}

void Shader::use() {
	glUseProgram(this->ID);
}
void Shader::setBool(const std::string &name, bool value) const
{
	glUniform1i(glGetUniformLocation(this->ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string &name, int value) const
{
	glUniform1i(glGetUniformLocation(this->ID, name.c_str()), value);
}
void Shader::setFloat(const std::string &name, float value) const
{
	glUniform1f(glGetUniformLocation(this->ID, name.c_str()), value);
}

分理出Shader.hCamera.h头文件后的代码:

Camera.h

#pragma once
#include 
#include 
#include 

#include 

enum Camera_Movement {
	FORWARD,
	BACKWARD,
	LEFT,
	RIGHT
};

const float YAW          = -90.0f;
const float PITCH        = 0.0f;
const float SPEED        = 5.5f;
const float SENSITIVATY  = 0.1f;
const float ZOOM         = 45.0f;

class Camera {
public:
	//摄像机属性
	glm::vec3 Position;
	glm::vec3 Front;
	glm::vec3 Up;
	glm::vec3 Right;
	glm::vec3 WorldUp;
	//欧拉角
	float Yaw;
	float Pitch;
	//摄像机设置
	float MovementSpeed;
	float MouseSensitivity;
	float Zoom;

	//参数是向量的构造函数
	Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f),
		glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f),
		float yaw = YAW,
		float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)),
			MovementSpeed(SPEED), 
			MouseSensitivity(SENSITIVATY), Zoom(ZOOM) {
		Position = position;
		WorldUp = up;
		Yaw = yaw;
		Pitch = pitch;
		updateCameraVectors();
	}
	//参数是标量的构造函数
	Camera(float posX, float posY, float posZ,
		float upX, float upY, float upZ, 
		float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)),
		MovementSpeed(SPEED),
		MouseSensitivity(SENSITIVATY), Zoom(ZOOM) {
		Position = glm::vec3(posX, posY, posZ);
		WorldUp = glm::vec3(upX, upY, upZ);
		Yaw = yaw;
		Pitch = pitch;
		updateCameraVectors();
	}
	glm::mat4 GetViewMatrix() {
		return glm::lookAt(Position, Position + Front, Up);
	}

	void ProcessKeyboard(Camera_Movement direction, float deltaTime) {
		float velocity = MovementSpeed * deltaTime;
		if (direction == FORWARD)
			Position += Front * velocity;
		if (direction == BACKWARD)
			Position -= Front * velocity;
		if (direction == LEFT)
			Position -= Right * velocity;
		if (direction == RIGHT)
			Position += Right * velocity;
	}

	void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrianPitch = true) {
		xoffset *= MouseSensitivity;
		yoffset *= MouseSensitivity;
		Yaw += xoffset;
		Pitch += yoffset;

		Pitch = Pitch > 89.0f ? 89.0f : Pitch;
		Pitch = Pitch < -89.0f ? -89.0f : Pitch;

		updateCameraVectors();
	}

	void ProcessMouseScroll(float yoffset) {
		if (Zoom >= 1.0f && Zoom <= 45.0f)
			Zoom -= yoffset;
		if (Zoom <= 1.0f)
			Zoom = 1.0f;
		if (Zoom >= 45.0f)
			Zoom = 45.0f;
	}
private:
	void updateCameraVectors() {
		glm::vec3 front;
		front.x = cos(glm::radians(Yaw))*cos(glm::radians(Pitch));
		front.y = sin(glm::radians(Pitch));
		front.z = sin(glm::radians(Yaw))*cos(glm::radians(Pitch));
		Front = glm::normalize(front);
		Right = glm::normalize(glm::cross(Front, WorldUp));
		Up = glm::normalize(glm::cross(Right, Front));
	}
};

Shader.h

#pragma once

#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 

class Shader {
public:
	GLuint ID;//程序ID

	//构造器读取并构建着色器
	Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
	//使用、激活程序
	void use();
	//uniform工具函数
	void setBool(const std::string &name, bool value) const;
	void setInt(const std::string &name, int value) const;
	void setFloat(const std::string &name, float value) const;
	void setMat4(const std::string &name, glm::mat4 mat) const;
};



Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath) {
	//从文件路径中获取顶点、片段着色器
	std::string vertexCode;//用来存储顶点着色器的字符串形式
	std::string fragmentCode;//用来存储片段着色器的字符串形式
	std::ifstream vShaderFile;//以输入方式打开
	std::ifstream fShaderFile;//以输入方式打开
	//保证ifstream对象可以抛出异常
	vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
	try {
		//打开文件
		vShaderFile.open(vertexPath);//以输入方式打开
		fShaderFile.open(fragmentPath);
		std::stringstream vShaderStream, fShaderStream;
		//读取文件的缓冲内容到数据流中
		vShaderStream << vShaderFile.rdbuf();
		fShaderStream << fShaderFile.rdbuf();
		//关闭文件处理器
		vShaderFile.close();
		fShaderFile.close();
		//转换数据流到string
		vertexCode = vShaderStream.str();//字符串流转换成字符串
		fragmentCode = fShaderStream.str();
	}
	catch (std::ifstream::failure e) {
		std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
	}
	const GLchar* vShaderCode = vertexCode.c_str();
	const GLchar* fShaderCode = fragmentCode.c_str();

	//编译着色器
	GLuint vertex, fragment;
	GLint success;
	GLchar infoLog[512];
	//VertexShader
	vertex = glCreateShader(GL_VERTEX_SHADER);
	glShaderSource(vertex, 1, &vShaderCode, NULL);
	glCompileShader(vertex);

	glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
	if (!success) {
		glGetShaderInfoLog(vertex, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
	}

	//fragmentShader
	fragment = glCreateShader(GL_FRAGMENT_SHADER);
	glShaderSource(fragment, 1, &fShaderCode, NULL);
	glCompileShader(fragment);

	glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
	if (!success)
	{
		glGetShaderInfoLog(fragment, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
	}

	//ShaderProgram
	this->ID = glCreateProgram();//产生着色器程序ID
	glAttachShader(this->ID, vertex);
	glAttachShader(this->ID, fragment);
	glLinkProgram(this->ID);

	glGetProgramiv(this->ID, GL_LINK_STATUS, &success);
	if (!success) {
		glGetProgramInfoLog(this->ID, 512, NULL, infoLog);
		std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED...\n" << infoLog << std::endl;
	}
	glDeleteShader(vertex);
	glDeleteShader(fragment);
}

void Shader::use() {
	glUseProgram(this->ID);
}
void Shader::setBool(const std::string &name, bool value) const
{
	glUniform1i(glGetUniformLocation(this->ID, name.c_str()), (int)value);
}
void Shader::setInt(const std::string &name, int value) const
{
	glUniform1i(glGetUniformLocation(this->ID, name.c_str()), value);
}
void Shader::setFloat(const std::string &name, float value) const
{
	glUniform1f(glGetUniformLocation(this->ID, name.c_str()), value);
}
void Shader::setMat4(const std::string &name, glm::mat4 mat) const
{
	glUniformMatrix4fv(glGetUniformLocation(this->ID, name.c_str()), 1,GL_FALSE,glm::value_ptr(mat));
}

main.cpp


#include 
#include 
#include 
#define STB_IMAGE_IMPLEMENTATION
#include 
#include "Shader.h"
#include "Camera.h"

#include 
#include 
#include 

#pragma comment(lib,"glfw3.lib")

using namespace std;

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void processInput(GLFWwindow* window);

const GLuint Width = 800, Height = 600;

//摄像机
Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));//初始化摄像机位置
float lastX = Width / 2.0f;
float lastY = Height / 2.0f;
bool firstMouse = true;

//计时器
GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;


int main() {
	glfwInit();
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	//创建窗口对象
	GLFWwindow* window = glfwCreateWindow(Width, Height, "LearnOpenGL", NULL, NULL);
	if (window == NULL) {
		cout << "Failed to create GLFW window" << endl;
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);//绑定上下文到此窗口
	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);//注册回调函数
	glfwSetCursorPosCallback(window, mouse_callback);//注册回调函数
	glfwSetScrollCallback(window, scroll_callback);//注册回调函数

	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);//隐藏光标

	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)){
		cout << "Failed to initialize GLAD" << endl;
		return -1;
	}


	//开启深度测试
	glEnable(GL_DEPTH_TEST);
	
	Shader ShaderColor("shader.vs","shader.frag");//创建并编译着色器
	
	//顶点数组
	GLfloat vertices[] = {
		// 第一个三角形     texture
		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, 0.0f, 1.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, 0.0f, // 左下角
		  0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		0.5f, -0.5f,  0.5f, 1.0f, 0.0f,  // 右下角
		//第四个三角形
		0.5f, -0.5f,  0.5f, 0.0f, 0.0f,  // 右下角
		0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		0.5f, -0.5f, -0.5f,  1.0f, 0.0f,  // 右上角
		//第五个三角形
		0.5f, -0.5f, -0.5f,  0.0f, 0.0f,  // 右上角
		0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		-0.5f,-0.5f, -0.5f, 1.0f, 0.0f, // 左上角
		//第六个三角形
		-0.5f,-0.5f, -0.5f, 0.0f, 0.0f,  // 左上角
		0.0f,  0.2f,  0.0f, 0.5f, 1.0f, // 顶点
		-0.5f, -0.5f, 0.5f, 1.0f, 0.0f  // 左下角
	}; 
	//模型位置数组
	glm::vec3 cubePositions[] = {
		  glm::vec3(0.0f,  0.0f,  0.0f),
		  glm::vec3(1.0f,  1.0f, 0.0f),
		  glm::vec3(-1.5f, -2.2f, -2.5f),
		  glm::vec3(-3.8f, -2.0f, -3.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)
	};
	
	GLuint VAO, VBO;
	glGenVertexArrays(1, &VAO);//创建顶点数组对象
	glGenBuffers(1, &VBO);//创建顶点缓冲对象

	glBindBuffer(GL_ARRAY_BUFFER, VBO);//将顶点缓冲绑定到顶点缓冲对象
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//缓冲区三角形顶点数据

	glBindVertexArray(VAO);//将顶点数组绑定到顶点数组对象
	//设置顶点属性指针
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 );
	glEnableVertexAttribArray(1);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);

	//纹理
	GLuint texture[3];
	glGenTextures(3, texture);
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	//为当前绑定的对象设置环绕,过滤方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	//加载并生成纹理一
	int width, height, nrChannels;
	stbi_set_flip_vertically_on_load(true);//在图像加载时帮助我们翻转y轴,只需要在加载任何图像前加入以下语句即可
	unsigned char *image1 = stbi_load("box2.png", &width, &height, &nrChannels, 0);
	cout << "Channels = " << nrChannels << endl;
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	if (image1) {
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		std::cout << "Failed to load texture1" << std::endl;
	}
	stbi_image_free(image1);
	glBindTexture(GL_TEXTURE_2D, 0);
	//加载并生成纹理二
	unsigned char *image2 = stbi_load("box.jpg", &width, &height, &nrChannels, 0);
	cout << "Channels = " << nrChannels << endl;
	glBindTexture(GL_TEXTURE_2D, texture[1]);
	if (image2) {
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image2);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		std::cout << "Failed to load texture2" << std::endl;
	}
	stbi_image_free(image2);
	glBindTexture(GL_TEXTURE_2D, 0);
	//加载并生成纹理三
	unsigned char *image3 = stbi_load("face.png", &width, &height, &nrChannels, 0);
	cout << "Channels = " << nrChannels << endl;
	glBindTexture(GL_TEXTURE_2D, texture[2]);
	if (image3) {
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image3);
		glGenerateMipmap(GL_TEXTURE_2D);
	}
	else {
		std::cout << "Failed to load texture3" << std::endl;
	}
	stbi_image_free(image3);
	glBindTexture(GL_TEXTURE_2D, 0);

	//int flagLoc = glGetUniformLocation(ShaderColor.ID, "flag");//此处不再需要获取地址了
	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	ShaderColor.use();
	ShaderColor.setInt("ourTexture0", 0);//设置采样器ourTexture0属于0号纹理单元
	ShaderColor.setInt("ourTexture1", 1);//设置采样器ourTexture1属于1号纹理单元
	ShaderColor.setInt("ourTexture2", 2);//设置采样器ourTexture2属于2号纹理单元

	
	while (!glfwWindowShouldClose(window)) {

		GLfloat currentFrame = glfwGetTime();
		deltaTime = currentFrame - lastFrame;//当前帧与上一帧的时间差
		lastFrame = currentFrame;//上一帧的时间

		processInput(window);

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

		ShaderColor.use();

		//变换矩阵
		glm::mat4 model = glm::mat4(1.0f);
		glm::mat4 view = glm::mat4(1.0f);
		glm::mat4 projection = glm::mat4(1.0f);
		//GLuint modelLoc = glGetUniformLocation(ShaderColor.ID, "model");
		//GLuint viewLoc = glGetUniformLocation(ShaderColor.ID, "view");
		GLuint projectionLoc = glGetUniformLocation(ShaderColor.ID, "projection");
		//model = glm::rotate(model, (float)-glfwGetTime()*60.0f, glm::vec3(1.0f, 0.0f, 0.0f));
		//view = glm::translate(view, glm::vec3(0.0f, 0.0f, -1.5f));
		projection = glm::perspective(glm::radians(camera.Zoom), (GLfloat)Width / Height, 0.1f, 100.0f);

		
		view = glm::lookAt(camera.Position, camera.Position + camera.Front, camera.Up);



		//glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
		ShaderColor.setMat4("view", view);
		//glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
		ShaderColor.setMat4("projection", projection);

		glBindVertexArray(VAO);//绑定顶点数组
		for (GLuint i = 0; i < 10; i++) {
			model = glm::translate(model, cubePositions[i]);
			model = glm::rotate(model, (float)i*10.0f, glm::vec3(0.0, 1.0, 0.0));
			//glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
			ShaderColor.setMat4("model", model);
			ShaderColor.setInt("flag", 1);
			glActiveTexture(GL_TEXTURE1);//激活0号纹理
			glBindTexture(GL_TEXTURE_2D, texture[1]);//绑定1号纹理为texture[1]
			glActiveTexture(GL_TEXTURE2);//激活1号纹理
			glBindTexture(GL_TEXTURE_2D, texture[2]);//绑定2号纹理为texture[2]
			glDrawArrays(GL_TRIANGLES, 0, 3);//右上三角形


			ShaderColor.setInt("flag", 2);
			glActiveTexture(GL_TEXTURE0);//激活0号纹理
			glBindTexture(GL_TEXTURE_2D, texture[0]);//绑定0号纹理为texture[0]
			glDrawArrays(GL_TRIANGLES, 3, 3);//左下三角形

			ShaderColor.setInt("flag", 3);
			glActiveTexture(GL_TEXTURE0);//激活0号纹理
			glBindTexture(GL_TEXTURE_2D, texture[0]);//绑定0号纹理为texture[0]
			glDrawArrays(GL_TRIANGLES, 6, 12);//左下三角形
		}
		

		glBindVertexArray(0);//解绑顶点数组
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	glDeleteBuffers(1, &VBO);
	glDeleteVertexArrays(1, &VAO);
	glfwTerminate();
	return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
	glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
		glfwSetWindowShouldClose(window, true);


	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
		camera.ProcessKeyboard(FORWARD, deltaTime);
	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
		camera.ProcessKeyboard(BACKWARD, deltaTime);
	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
		camera.ProcessKeyboard(LEFT, deltaTime);
	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
		camera.ProcessKeyboard(RIGHT, deltaTime);
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
	if (firstMouse)
	{
		lastX = xpos;
		lastY = ypos;
		firstMouse = false;
	}

	float xoffset = xpos - lastX;
	float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
	lastX = xpos;
	lastY = ypos;

	camera.ProcessMouseMovement(xoffset, yoffset);
}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
	camera.ProcessMouseScroll(yoffset);
}

OpenGL之——3D漫游(金字塔)_第3张图片

你可能感兴趣的:(OpenGL,C++语言学习)