main.cpp
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <assert.h>
#include <cmath>
#include <stack>
#include <vector>
#include <Class/Shader/Shader.h>
#include <Class/Camera/Camera.h>
// 创建多少个 VAO VBO
#define ARRAYMAXCOUNT 1
// 创建 vao 变量
GLuint vao[ARRAYMAXCOUNT+1];
// 创建 vbo
GLuint vbo[ARRAYMAXCOUNT];
// 创建着色器类
Shader shader1;
Shader shader2;
// 位置、目标、上向量
Camera myCamera(glm::vec3(0.0f, 0.0f, 3.0f),glm::vec3(0.0f, 0.0f, -1.0f),glm::vec3(0.0f, 1.0f, 0.0f));
GLuint
texture1,// 纹理
texture2,// 纹理
mvLoad,// mv矩阵(视图矩阵 * 模型矩阵)
pLoad;// 透视矩阵
glm::mat4
mMat, // 模型矩阵
pMat, // 透视矩阵
vMat; // 视图矩阵
// 光源位置
glm::vec3 lightPos(-0.2f, -1.0f, -0.3f);
// 10 个箱子的位置
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 init(GLFWwindow* window);
// 渲染自定义代码
void display(GLFWwindow* window, double currentTime);
// 销毁
void destroy(GLFWwindow* window);
// 窗口改变事件
void window_reshape_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);
int main() {
// 初始化 glfw
if (!glfwInit()) { exit(EXIT_FAILURE); }
// 设置 opengl 版本 (4.6 核心)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 创建 window 窗口
GLFWwindow* window = glfwCreateWindow(600, 600, "LearOpenGL 1.4", NULL, NULL);
// 链接 opengl 上下文
glfwMakeContextCurrent(window);
// 初始化 glad 获取 opengl api 函数 地址
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { exit(EXIT_FAILURE); }
// 开启垂直
glfwSwapInterval(1);
// 注册窗口改变事件
glfwSetWindowSizeCallback(window, window_reshape_callback);
// 隐藏光标
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
// 注册了鼠标移动事件
glfwSetCursorPosCallback(window, mouse_callback);
// 注册了鼠标滚动事件
glfwSetScrollCallback(window, scroll_callback);
// 初始化着色器类
shader1.init("vertShader1.glsl","fragShader1.glsl");
shader2.init("vertShader2.glsl","fragShader2.glsl");
// 初始自定义代码
init(window);
myCamera.fov = 45.0f;
// 循环渲染
while (!glfwWindowShouldClose(window))
{
// 监听键盘
ProcessInput(window);
// 渲染自定义代码
display(window, glfwGetTime());
// 交换缓存和轮询IO事件
glfwSwapBuffers(window);
glfwPollEvents();
}
// 释放内存
destroy(window);
// 成功退出程序
exit(EXIT_SUCCESS);
}
void init(GLFWwindow* window) {
// 创建 vao
glGenVertexArrays(ARRAYMAXCOUNT+1, vao);
// 创建 vbo
glGenBuffers(ARRAYMAXCOUNT, vbo);
float vertices[] = {
// 顶点 // 法向量 // 纹理
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
// 绑定 vao
glBindVertexArray(vao[0]);
// 把顶点数据绑定到 vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, 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*)(sizeof(float) * 3));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(sizeof(float) * 6));
glEnableVertexAttribArray(2);
// 绑定 vao
glBindVertexArray(vao[1]);
// 把顶点数据绑定到 vbo
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 设置属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 创建纹理
glGenTextures(1, &texture1);
Utils::image image;
image.imagePath = "dm\\container2.png";
image.Isreversed = true;
image.type = GL_RGBA;
// 绑定纹理
glBindTexture(GL_TEXTURE_2D, texture1);
Utils::getImage(image);
glGenTextures(1, &texture2);
image.imagePath = "dm\\container2_specular.png";
glBindTexture(GL_TEXTURE_2D, texture2);
Utils::getImage(image);
// 开启着色器程序
shader1.useProgram();
mvLoad = shader1.getULocation("mv_matrix");
pLoad = shader1.getULocation("p_matrix");
// 材质颜色结构体
shader1.setPUInt("material.diffuse", 0); // 漫反射光照
shader1.setPUInt("material.specular", 1);// 镜面光照
shader1.setPUFloat("material.shininess", 32.0f);// 反光度
// 光源颜色结构体
shader1.setPUF3fv_t("light.ambient", glm::value_ptr(glm::vec3(0.2f, 0.2f, 0.2f)));// 环境光照
shader1.setPUF3fv_t("light.diffuse", glm::value_ptr(glm::vec3(0.5f, 0.5f, 0.5f)));// 漫反射光照
shader1.setPUF3fv_t("light.specular", glm::value_ptr(glm::vec3(1.0f, 1.0f, 1.0f)));// 镜面光照
shader1.setPUF3fv_t("light.direction", glm::value_ptr(lightPos));
// 获取窗口的宽高
int width, height;
glfwGetFramebufferSize(window, &width, &height);// 获取屏幕宽,高
// 计算宽高比
float aspect = (float)width / (float)height;//获取屏幕比例
// 创建透视矩阵 / 设置投影矩阵
pMat = glm::perspective(glm::radians(myCamera.fov), aspect, 0.1f, 1000.0f);
}
void display(GLFWwindow* window, double currentTime) {
// 填充颜色缓冲区
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// 清除深度缓冲区
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
// 创建透视矩阵 / 设置投影矩阵
pMat = glm::perspective(glm::radians(myCamera.fov), (float)600 / (float)600, 0.1f, 1000.0f);
// 开启着色器程序
shader1.useProgram();
// 将视图矩阵压入栈
vMat = myCamera.getLookAt();
// 透视矩阵
shader1.setPUFMat4(pLoad, glm::value_ptr(pMat));
// 将纹理绑定到相应的纹理单元上
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
// 开启深度测试
glEnable(GL_DEPTH_TEST);
// 设置深度测试的比较方式
glDepthFunc(GL_LEQUAL);
// 绑定 vao
glBindVertexArray(vao[0]);
for (int i = 1; i <= 10; i++)
{
// 模型矩阵
mMat = glm::translate(glm::mat4(1.0f), cubePositions[i - 1]);
float angle = 20.0f * i * currentTime * 0.5f;
mMat = glm::rotate(mMat, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
// mv 矩阵
shader1.setPUFMat4(mvLoad, glm::value_ptr(vMat * mMat));
// 绘制模型
glDrawArrays(GL_TRIANGLES, 0, 36);
}
// 开启着色器程序
shader2.useProgram();
// 模型矩阵
mMat = glm::translate(glm::mat4(1.0f), -lightPos);
mMat = glm::rotate(mMat, (float)currentTime * glm::radians(45.0f), glm::vec3(1.0f, 0.5f, 0.0f));
mMat = glm::scale(mMat, glm::vec3(0.2f, 0.2f, 0.2f));
shader2.setPUFMat4("mv_matrix", glm::value_ptr(vMat * mMat));
shader2.setPUFMat4("p_matrix", glm::value_ptr(pMat));
shader2.setPUFloat("lightColor", 1.0f, 1.0f, 1.0f);
// 开启深度测试
glEnable(GL_DEPTH_TEST);
// 设置深度测试的比较方式
glDepthFunc(GL_LEQUAL);
// 绑定 vao
glBindVertexArray(vao[1]);
// 绘制模型
glDrawArrays(GL_TRIANGLES, 0, 36);
}
void destroy(GLFWwindow* window) {
// 销毁 vao vbo
glDeleteVertexArrays(ARRAYMAXCOUNT, vao);
glDeleteBuffers(ARRAYMAXCOUNT, vbo);
// 销毁着色器
shader1.deleteProgram();
// 销毁窗口
glfwDestroyWindow(window);
glfwTerminate();
}
void window_reshape_callback(GLFWwindow* window, int width, int height)
{
// 设置和帧缓冲区相关的屏幕区域
glViewport(0, 0, width, height);
}
// 监听按键,鼠标事件
void ProcessInput(GLFWwindow* window)
{
// 检查用户是否按下了返回键(Esc)
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
// 下一次while循环的条件检测将会失败,程序将会关闭
glfwSetWindowShouldClose(window, true);
}
static float deltaTime = 0.0f;
static float lastFrame = 0.0f;
float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame; // 当前帧与上一帧的时间差
lastFrame = currentFrame; // 上一帧的时间
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
myCamera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
myCamera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
myCamera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
myCamera.ProcessKeyboard(RIGHT, deltaTime);
}
// 回调函数,鼠标进入程序窗口,获取焦点
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
static bool firstMouse = true;
static float lastX = 0.0f;
static float lastY = 0.0f;
static float xoffset = 0.0f;
static float yoffset = 0.0f;
if (firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}
// 获取 x 坐标
xoffset = xpos - lastX;
// 注意这里是相反的,因为y坐标是从底部往顶部依次增大的
yoffset = lastY - ypos;
// 更新鼠标坐标
lastX = xpos;
lastY = ypos;
myCamera.mouse_callback(xoffset, yoffset);
}
// 监听鼠标滚动
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
myCamera.scroll_callback(xoffset, yoffset);
}
Camera.cpp
#include "Camera.h"
// 构造函数,初始化摄像机的位置、方向和观察矩阵
Camera::Camera(glm::vec3 pos, glm::vec3 front, glm::vec3 up) : cameraPos(pos), cameraFront(front), cameraUp(up)
{
pitch = 0.0f;
yaw = -90.0f;
sensitivity = 0.05f;
fov = 60.0f;
fovMax = 1000.0f;
MovementSpeed = 2.5f;
this->front = glm::vec3(1.0f);
}
// 获取观察矩阵
glm::mat4 Camera::getLookAt(bool custom)
{
if (custom)
{
// 摄像机方向(z)
glm::vec3 f = glm::vec3(glm::normalize(cameraFront));
// 右轴(x)
glm::vec3 s = glm::vec3(glm::normalize(glm::cross(f, cameraUp)));
// 上轴(y)
glm::vec3 u = glm::vec3(glm::cross(s, f));
return glm::mat4(
s.x, u.x, -f.x, 0,
s.y, u.y, -f.y, 0,
s.z, u.z, -f.z, 0,
-glm::dot(s, cameraPos), -glm::dot(u, cameraPos), glm::dot(f, cameraPos), 1);
}
return glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp);
}
// 处理输入,处理按键、鼠标滚动、移动设备等输入
void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float cameraSpeed = MovementSpeed * deltaTime;
// 处理按键输入
if (direction == FORWARD)
cameraPos += cameraSpeed * cameraFront;
if (direction == BACKWARD)
cameraPos -= cameraSpeed * cameraFront;
if (direction == LEFT)
cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
if (direction == RIGHT)
cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}
// 处理鼠标滚动输入
void Camera::mouse_callback(double xoffset, double yoffset, bool constrainPitch)
{
// 灵敏度值。
xoffset *= sensitivity;
yoffset *= sensitivity;
// 设置摄像机的旋转角度
yaw += xoffset;
pitch += yoffset;
// 限制摄像机的俯仰角度
if (constrainPitch)
{
// 保证用户只能看到天空或脚下,这样也会避免一些奇怪的问题
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
}
// 计算观察矩阵
this->CalculateMatrixObs();
}
// 处理鼠标滚动输入
void Camera::scroll_callback(double xoffset, double yoffset)
{
fov -= yoffset;
if (fov <= 0.1f)
fov = 0.1f;
if (fov >= fovMax)
fov = fovMax;
}
// 计算观察矩阵
void Camera::CalculateMatrixObs()
{
// 译注:direction代表摄像机的前轴(Front),这个前轴是和本文第一幅图片的第二个摄像机的方向向量是相反的
front.x = cos(glm::radians(pitch)) * cos(glm::radians(yaw));
// 注意我们先把角度转为弧度
front.y = sin(glm::radians(pitch));
front.z = cos(glm::radians(pitch)) * sin(glm::radians(yaw));
cameraFront = glm::normalize(front);
}
Camera.h
#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
enum Camera_Movement {
FORWARD, // 上
BACKWARD, // 下
LEFT, // 左
RIGHT // 右
};
class Camera
{
private:
glm::vec3 front;
// 计算观察矩阵
void CalculateMatrixObs();
public:
glm::vec3 cameraPos; // 摄像机位置
glm::vec3 cameraFront; // 方向向量
glm::vec3 cameraUp; // 上向量
float sensitivity; // 灵敏度值。
float yaw; // 偏航角 x
float pitch; // 俯仰角 y
float fov; // 视锥体的角度
float fovMax;
float MovementSpeed; // 移动速度
Camera(glm::vec3 pos = glm::vec3(0.0f, 0.0f, 3.0f), glm::vec3 front = glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f));
// 获取 lookAt 矩阵
glm::mat4 getLookAt(bool custom = false);
// 回调函数,鼠标进入程序窗口,获取焦点
void mouse_callback(double xoffset, double yoffset, bool constrainPitch = true);
// 监听按键,鼠标事件
void ProcessKeyboard(Camera_Movement direction, float deltaTime);
// 监听鼠标滚动
void scroll_callback(double xoffset, double yoffset);
};