OpenGL摄像机类

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);
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值