这学期的计算机图形学需要使用 OpenGL ,我参照 LearnOpenGL CN 配置好了环境,但是在使用 Visual Studio 写代码的过程中,发现很不顺手(是 JetBrains 的 CLion 太好用了),就想着用 CLion 再次配置一下。
因为 CLion 的构建工具是 CMake ,我不是很懂这个,就去查了很多资料,忙活了一下午才弄好,写下来怕忘了。
请先按照 Learn OpenGL 的官方教程用 Visual Studio 配置,下面所有步骤建立在 VS 环境配置好的基础上
Table of contents
Open Table of contents
创建新项目
创建 C++ Executable 项目,命名为 opengl-project ,刚创建完的 CMakelist.txt 应该是这样的
cmake_minimum_required(VERSION 3.21)project(opengl_project)
set(CMAKE_CXX_STANDARD 11)
add_executable(opengl_project main.cpp)修改编译工具为 VS
在 Settings -> Build, Executable, Deployment -> Toolchains 中添加 Visual Studio ,
Toolset 选择 VS 安装路径, Architecture 选择 amd64,其他保持默认即可

添加 include 和 lib 目录
将头文件和库文件添加到项目目录下
├─cmake-build-debug├─include│ ├─glad│ ├─GLFW│ ├─glm│ ├─KHR│ └─stb_image.h├─lib│ └─glfw3.lib├─CMakeLists.txt├─glad.c└─main.cpp在 CMakeLists.txt 中添加这两个目录
include_directories(include)link_directories(lib)set(option glfw3 opengl32) # link option示例程序
hello triangle 程序
新建文件 hello_triangle.cpp
//// Created by wjl15 on 2022/4/9.//
#include <glad/glad.h>#include <GLFW/glfw3.h>#include <iostream>
void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height);}
void process_input(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); }}
const unsigned int WIDTH = 800;const unsigned int HEIGHT = 600;
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" "{\n" " FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n" "}\n\0";
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", nullptr, nullptr); if (window == nullptr) { std::cout << "Failed to create GLFW window\n"; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) { std::cout << "Failed to initilize GLAD\n"; return -1; }
unsigned int vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, &vertexShaderSource, nullptr); glCompileShader(vertex_shader); int success; char info_log[512]; glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertex_shader, 512, nullptr, info_log); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << info_log << "\n"; } unsigned int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fragmentShaderSource, nullptr); glCompileShader(fragment_shader); glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragment_shader, 512, nullptr, info_log); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << info_log << "\n"; }
unsigned int shader_program = glCreateProgram(); glAttachShader(shader_program, vertex_shader); glAttachShader(shader_program, fragment_shader); glLinkProgram(shader_program); glGetProgramiv(shader_program, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shader_program, 512, nullptr, info_log); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << info_log << "\n"; } glDeleteShader(vertex_shader); glDeleteShader(fragment_shader);
float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f };
unsigned int vbo, vao; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0);
while (!glfwWindowShouldClose(window)) { process_input(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader_program); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window); glfwPollEvents(); }
glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); glDeleteProgram(shader_program);
glfwTerminate(); return 0;}在 CMakeLists.txt 中添加构建目标
add_executable(hello_triangle hello_triangle.cpp glad.c)target_link_libraries(hello_triangle ${option})运行结果

shader class 程序
新建文件 shader_class.cpp ,在这个程序里我们调用外部着色器文件
添加 GLSL 插件
写着色器代码就有高亮了

编写 shader 类
创建 shader.h 头文件
//// Created by wjl15 on 2022/4/9.//
#ifndef OPENGL_PROJECT_SHADER_H#define OPENGL_PROJECT_SHADER_H
#include <glad/glad.h>#include <glm/glm.hpp>#include <fstream>#include <iostream>#include <sstream>#include <string>
class shader {private: static void check_compile_errors(GLuint shader, const std::string &type);
public: unsigned int id;
shader(const char *vertex_path, const char *fragment_path, const char *geometry_path = nullptr);
void use() const; void set_bool(const std::string &name, bool value) const; void set_int(const std::string &name, int value) const; void set_float(const std::string &name, float value) const;
void set_vec2(const std::string &name, const glm::vec2 &value) const; void set_vec2(const std::string &name, float x, float y) const; void set_vec3(const std::string &name, const glm::vec3 &value) const; void set_vec3(const std::string &name, float x, float y, float z) const; void set_vec4(const std::string &name, const glm::vec4 &value) const; void set_vec4(const std::string &name, float x, float y, float z, float w) const; void set_mat2(const std::string &name, const glm::mat2 &mat) const; void set_mat3(const std::string &name, const glm::mat3 &mat) const; void set_mat4(const std::string &name, const glm::mat4 &mat) const;};
void shader::check_compile_errors(const GLuint shader, const std::string &type) { GLint success; GLchar info_log[1024]; if (type != "PROGRAM") { glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 1024, nullptr, info_log); std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << info_log << "\n"; } } else { glGetProgramiv(shader, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shader, 1024, nullptr, info_log); std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << info_log << "\n"; } }}
shader::shader(const char *vertex_path, const char *fragment_path, const char *geometry_path) { std::string vertex_code; std::string fragment_code; std::string geometry_code; std::ifstream v_shader_file; std::ifstream f_shader_file; std::ifstream g_shader_file;
v_shader_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); f_shader_file.exceptions(std::ifstream::failbit | std::ifstream::badbit); g_shader_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try { v_shader_file.open(vertex_path); f_shader_file.open(fragment_path); std::stringstream v_shader_stream, f_shader_stream; v_shader_stream << v_shader_file.rdbuf(); f_shader_stream << f_shader_file.rdbuf(); v_shader_file.close(); f_shader_file.close(); vertex_code = v_shader_stream.str(); fragment_code = f_shader_stream.str(); if (geometry_path != nullptr) { g_shader_file.open(geometry_path); std::stringstream g_shader_stream; g_shader_stream << g_shader_file.rdbuf(); g_shader_file.close(); geometry_code = g_shader_stream.str(); } } catch (std::ifstream::failure &e) { std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << "\n"; }
const char *v_shader_code = vertex_code.c_str(); const char *f_shader_code = fragment_code.c_str(); unsigned int vertex, fragment;
vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &v_shader_code, nullptr); glCompileShader(vertex); check_compile_errors(vertex, "VERTEX"); fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &f_shader_code, nullptr); glCompileShader(fragment); check_compile_errors(fragment, "FRAGMENT");
unsigned int geometry = 0; if (geometry_path != nullptr) { const char *g_shader_code = geometry_code.c_str(); geometry = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(geometry, 1, &g_shader_code, nullptr); glCompileShader(geometry); check_compile_errors(geometry, "GEOMETRY"); }
id = glCreateProgram(); glAttachShader(id, vertex); glAttachShader(id, fragment); if (geometry_path != nullptr) { glAttachShader(id, geometry); } glLinkProgram(id); check_compile_errors(id, "PROGRAM");
glDeleteShader(vertex); glDeleteShader(fragment); if (geometry_path != nullptr) { glDeleteShader(geometry); }}
void shader::use() const { glUseProgram(id);}
void shader::set_bool(const std::string &name, const bool value) const { glUniform1i(glGetUniformLocation(id, name.c_str()), static_cast<int>(value));}
void shader::set_int(const std::string &name, const int value) const { glUniform1i(glGetUniformLocation(id, name.c_str()), value);}
void shader::set_float(const std::string &name, const float value) const { glUniform1f(glGetUniformLocation(id, name.c_str()), value);}
void shader::set_vec2(const std::string &name, const glm::vec2 &value) const { glUniform2fv(glGetUniformLocation(id, name.c_str()), 1, &value[0]);}
void shader::set_vec2(const std::string &name, const float x, const float y) const { glUniform2f(glGetUniformLocation(id, name.c_str()), x, y);}
void shader::set_vec3(const std::string &name, const glm::vec3 &value) const { glUniform3fv(glGetUniformLocation(id, name.c_str()), 1, &value[0]);}
void shader::set_vec3(const std::string &name, const float x, const float y, const float z) const { glUniform3f(glGetUniformLocation(id, name.c_str()), x, y, z);}
void shader::set_vec4(const std::string &name, const glm::vec4 &value) const { glUniform4fv(glGetUniformLocation(id, name.c_str()), 1, &value[0]);}
void shader::set_vec4(const std::string &name, const float x, const float y, const float z, const float w) const { glUniform4f(glGetUniformLocation(id, name.c_str()), x, y, z, w);}
void shader::set_mat2(const std::string &name, const glm::mat2 &mat) const { glUniformMatrix2fv(glGetUniformLocation(id, name.c_str()), 1, GL_FALSE, &mat[0][0]);}
void shader::set_mat3(const std::string &name, const glm::mat3 &mat) const { glUniformMatrix3fv(glGetUniformLocation(id, name.c_str()), 1, GL_FALSE, &mat[0][0]);}
void shader::set_mat4(const std::string &name, const glm::mat4 &mat) const { glUniformMatrix4fv(glGetUniformLocation(id, name.c_str()), 1, GL_FALSE, &mat[0][0]);}
#endif//OPENGL_PROJECT_SHADER_H添加 shader 目录
统一存放着色器文件
├─cmake-build-debug├─include│ ├─glad│ ├─GLFW│ ├─glm│ ├─KHR│ └─stb_image.h├─lib│ └─glfw3.lib├─shader├─CMakeLists.txt├─glad.c└─main.cpp在 shader 路径下新建 3-3.vert 和 3-3.frag 着色器文件
#version 330 core
layout (location = 0) in vec3 aPos;layout (location = 1) in vec3 aColor;
out vec3 ourColor;
void main() { gl_Position = vec4(aPos, 1.0); ourColor = aColor;}///////////////////////////////////////
// 3-3.frag#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main() { FragColor = vec4(ourColor, 1.0f);}程序代码
//// Created by wjl15 on 2022/4/9.//
#include <glad/glad.h>#include <GLFW/glfw3.h>#include <iostream>#include "shader.h"
void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height);}
void process_input(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); }}
const unsigned int WIDTH = 800;const unsigned int HEIGHT = 600;
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", nullptr, nullptr); if (window == nullptr) { std::cout << "Failed to create GLFW window\n"; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) { std::cout << "Failed to initilize GLAD\n"; return -1; }
shader our_shader("shader/3-3.vert", "shader/3-3.frag");
float vertices[] = { 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f };
unsigned int vbo, vao; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
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);
while (!glfwWindowShouldClose(window)) { process_input(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
our_shader.use(); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 3);
glfwSwapBuffers(window); glfwPollEvents(); }
glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo);
glfwTerminate(); return 0;}在 CMakeLists.txt 中添加构建目标
add_executable(shader_class shader_class.cpp glad.c)target_link_libraries(shader_class ${option})file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/shader DESTINATION ${CMAKE_CURRENT_BINARY_DIR})运行结果

textures combined 程序
新建文件 textures_combined.cpp ,在这个程序里我们加载和创建纹理
添加 image 目录
统一存放 图片文件
├─cmake-build-debug├─include│ ├─glad│ ├─GLFW│ ├─glm│ ├─KHR│ └─stb_image.h├─lib│ └─glfw3.lib├─shader├─image├─CMakeLists.txt├─glad.c└─main.cpp添加图片 container.jpg 和 awesomeface.png
编写着色器文件
创建 4-2.vert 和 4-2.frag 文件
#version 330 core
layout (location = 0) in vec3 aPos;layout (location = 1) in vec3 aColor;layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;out vec2 TexCoord;
void main() { gl_Position = vec4(aPos, 1.0); ourColor = aColor; TexCoord = vec2(aTexCoord.x, aTexCoord.y);}
///////////////////////////////////////
// 4-2.frag#version 330 core
out vec4 FragColor;
in vec3 ourColor;in vec2 TexCoord;
uniform sampler2D texture1;uniform sampler2D texture2;
void main() { FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);}程序代码
//// Created by wjl15 on 2022/4/9.//
#include <glad/glad.h>#include <GLFW/glfw3.h>#define STB_IMAGE_IMPLEMENTATION#include <stb_image.h>#include <iostream>#include "shader.h"
void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height);}
void process_input(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); }}
const unsigned int WIDTH = 800;const unsigned int HEIGHT = 600;
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", nullptr, nullptr); if (window == nullptr) { std::cout << "Failed to create GLFW window\n"; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) { std::cout << "Failed to initilize GLAD\n"; return -1; }
shader our_shader("shader/4-2.vert", "shader/4-2.frag");
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 };
unsigned int indices[] = { 0, 1, 3, 1, 2, 3 };
unsigned int vbo, vao, ebo; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glGenBuffers(1, &ebo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 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);
unsigned int texture1, texture2;
glGenTextures(1, &texture1); glBindTexture(GL_TEXTURE_2D, texture1); 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); unsigned char *data = stbi_load("image/container.jpg", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture\n"; } stbi_image_free(data);
glGenTextures(1, &texture2); glBindTexture(GL_TEXTURE_2D, texture2); 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);
data = stbi_load("image/awesomeface.png", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture\n"; } stbi_image_free(data);
our_shader.use(); glUniform1i(glGetUniformLocation(our_shader.id, "texture1"), 0); our_shader.set_int("texture2", 1);
while (!glfwWindowShouldClose(window)) { process_input(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2);
our_shader.use(); glBindVertexArray(vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window); glfwPollEvents(); }
glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &ebo);
glfwTerminate(); return 0;}在 CMakeLists.txt 中添加构建目标
add_executable(textures_combined textures_combined.cpp glad.c)target_link_libraries(textures_combined ${option})file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/shader ${CMAKE_CURRENT_SOURCE_DIR}/image DESTINATION ${CMAKE_CURRENT_BINARY_DIR})运行结果

cameara class 程序
新建文件 camera_class.cpp ,在这个程序里我们调用摄像机类来浏览场景
编写 camera 类
创建 camera.h 头文件
//// Created by wjl15 on 2022/4/9.//
#ifndef OPENGL_PROJECT_CAMERA_H#define OPENGL_PROJECT_CAMERA_H
#include <glad/glad.h>#include <glm/glm.hpp>#include <glm/gtc/matrix_transform.hpp>#include <vector>
enum camera_movement { FORWARD, BACKWARD, LEFT, RIGHT};
const float YAM = -90.0f;const float PITCH = 0.0f;const float SPEED = 2.5f;const float SENSITIVITY = 0.1f;const float ZOOM = 45.0f;
class camera {private: void update_camera_vectors();
public: glm::vec3 position; glm::vec3 front; glm::vec3 up; glm::vec3 right; glm::vec3 world_up;
float yaw; float pitch; float movement_speed; float mouse_sensitivity; float zoom;
explicit camera(glm::vec3 _pos = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 _up = glm::vec3(0.0f, 1.0f, 0.0f), float _yam = YAM, float _pitch = PITCH) : front(glm::vec3(0.0f, 0.0f, -1.0f)), movement_speed(SPEED), mouse_sensitivity(SENSITIVITY), zoom(ZOOM) { position = _pos; world_up = _up; yaw = _yam; pitch = _pitch; update_camera_vectors(); }
camera(float pos_x, float pos_y, float pos_z, float up_x, float up_y, float up_z, float _yaw, float _pitch) : front(glm::vec3(0.0f, 0.0f, -1.0f)), movement_speed(SPEED), mouse_sensitivity(SENSITIVITY), zoom(ZOOM) { position = glm::vec3(pos_x, pos_y, pos_z); world_up = glm::vec3(up_x, up_y, up_z); yaw = _yaw; pitch = _pitch; update_camera_vectors(); }
glm::mat4 get_view_matrix() const;
void process_keyboard(camera_movement direction, float delta_time); void process_mouse_movement(float x_offset, float y_offset, GLboolean constrain_pitch = true); void process_mouse_scroll(float y_offset);};
void camera::update_camera_vectors() { 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, world_up)); up = glm::normalize(glm::cross(right, front));}
glm::mat4 camera::get_view_matrix() const { return glm::lookAt(position, position + front, up);}
void camera::process_keyboard(camera_movement direction, float delta_time) { float velocity = movement_speed * delta_time; 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 camera::process_mouse_movement(float x_offset, float y_offset, GLboolean constrain_pitch) { x_offset *= mouse_sensitivity; y_offset *= mouse_sensitivity; yaw += x_offset; pitch += y_offset; if (constrain_pitch) { if (pitch > 89.0f) { pitch = 89.0f; } if (pitch < -89.0f) { pitch = -89.0f; } } update_camera_vectors();}
void camera::process_mouse_scroll(float y_offset) { zoom -= (float) y_offset; if (zoom < 1.0f) { zoom = 1.0f; } if (zoom > 1.0f) { zoom = 45.0f; }}
#endif//OPENGL_PROJECT_CAMERA_H编写着色器文件
创建 7-1.vert 和 7-1.frag 文件
#version 330 core
layout (location = 0) in vec3 aPos;layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;uniform mat4 view;uniform mat4 projection;
void main() { gl_Position = projection * view * model * vec4(aPos, 1.0f); TexCoord = vec2(aTexCoord.x, aTexCoord.y);}
///////////////////////////////////////
// 7-1.frag#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D texture1;uniform sampler2D texture2;
void main() { FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2);}程序代码
//// Created by wjl15 on 2022/4/9.//
#include <glad/glad.h>#include <GLFW/glfw3.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 <iostream>#include "shader.h"#include "camera.h"
void framebuffer_size_callback(GLFWwindow *window, int width, int height);void mouse_callback(GLFWwindow *window, double x_pos_in, double y_pos_in);void scroll_callback(GLFWwindow *window, double x_offset, double y_offset);void process_input(GLFWwindow *window);
const unsigned int WIDTH = 800;const unsigned int HEIGHT = 600;
camera camera(glm::vec3(0.0f, 0.0f, 3.0f));float last_x = WIDTH / 2.0f;float last_y = HEIGHT / 2.0f;bool first_mouse = true;
float delta_time = 0.0f;float last_frame = 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", nullptr, nullptr); if (window == nullptr) { std::cout << "Failed to create GLFW window\n"; 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)) { std::cout << "Failed to initilize GLAD\n"; return -1; }
glEnable(GL_DEPTH_TEST);
shader our_shader("shader/7-1.vert", "shader/7-1.frag");
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 };
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) };
unsigned int vbo, vao; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(1);
unsigned int texture1, texture2;
glGenTextures(1, &texture1); glBindTexture(GL_TEXTURE_2D, texture1); 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); unsigned char *data = stbi_load("image/container.jpg", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture\n"; } stbi_image_free(data);
glGenTextures(1, &texture2); glBindTexture(GL_TEXTURE_2D, texture2); 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);
data = stbi_load("image/awesomeface.png", &width, &height, &nrChannels, 0); if (data) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); } else { std::cout << "Failed to load texture\n"; } stbi_image_free(data);
our_shader.use(); our_shader.set_int("texture1", 0); our_shader.set_int("texture2", 1);
while (!glfwWindowShouldClose(window)) { auto current_frame = static_cast<float>(glfwGetTime()); delta_time = current_frame - last_frame; last_frame = current_frame;
process_input(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, texture1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2);
our_shader.use();
glm::mat4 projection = glm::perspective(glm::radians(camera.zoom), (float) WIDTH / (float) HEIGHT, 0.1f, 100.0f); our_shader.set_mat4("projection", projection);
glm::mat4 view = camera.get_view_matrix(); our_shader.set_mat4("view", view);
glBindVertexArray(vao);
for (unsigned int i= 0; i < 5; i++) { glm::mat4 model = glm::mat4(1.0f); 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)); our_shader.set_mat4("model", model); glDrawArrays(GL_TRIANGLES, 0, 36); }
glfwSwapBuffers(window); glfwPollEvents(); }
glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo);
glfwTerminate(); return 0;}
void framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height);}
void mouse_callback(GLFWwindow *window, double x_pos_in, double y_pos_in) { float x_pos = static_cast<float>(x_pos_in); float y_pos = static_cast<float>(y_pos_in); if (first_mouse) { last_x = x_pos; last_y = y_pos; first_mouse = false; } float x_offset = x_pos - last_x; float y_offset = last_y - y_pos; last_x = x_pos; last_y = y_pos; camera.process_mouse_movement(x_offset, y_offset);}
void scroll_callback(GLFWwindow *window, double x_offset, double y_offset) { camera.process_mouse_scroll(static_cast<float>(y_offset));}
void process_input(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { camera.process_keyboard(FORWARD, delta_time); } if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { camera.process_keyboard(BACKWARD, delta_time); } if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { camera.process_keyboard(LEFT, delta_time); } if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { camera.process_keyboard(RIGHT, delta_time); }}在 CMakeLists.txt 中添加构建目标
add_executable(camera_class camera_class.cpp glad.c)target_link_libraries(camera_class ${option})file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/shader ${CMAKE_CURRENT_SOURCE_DIR}/image DESTINATION ${CMAKE_CURRENT_BINARY_DIR})运行结果

至此差不多基础配置都已完成,应该能正常写代码了
—完—