# Computer Graphics Second Experiment **Repository Path**: cyb_c/computer-graphics-second-experiment ## Basic Information - **Project Name**: Computer Graphics Second Experiment - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-14 - **Last Updated**: 2024-05-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 算机图形学第二次实验 ## 实验环境 使用Opengl作为应用程序编译接口,具体环境配置见实验手册。 ### 项目运行 配置好环境后,直接运行即可,主程序位于demo.cpp文件中。 ## 代码解析 对使用到的代码进行简单的解释 ### Shader 自定义了着色器,总实现代码如下,代码解析写于注释之中 ```c++ #ifndef SHADER_H #define SHADER_H #include #include #include #include #include #include #include #include // Shader 类,用于处理 GLSL 着色器的编译和管理 class Shader { public: unsigned int ID; // 着色器程序的ID引用 // 构造函数,读取并构建着色器,传入顶点和片段着色器文件路径 Shader(const char* vertexPath, const char* fragmentPath) { // 1. 从文件路径中获取顶点/片段着色器的源码 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(); // 转换流为字符串 vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); } catch (std::ifstream::failure& e) { // 如果文件未成功读取,打印错误信息 std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl; } const char* vShaderCode = vertexCode.c_str(); const char* fShaderCode = fragmentCode.c_str(); // 2. 编译着色器 unsigned int vertex, fragment; // 顶点着色器 vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vShaderCode, NULL); glCompileShader(vertex); checkCompileErrors(vertex, "VERTEX"); // 片段着色器 fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fShaderCode, NULL); glCompileShader(fragment); checkCompileErrors(fragment, "FRAGMENT"); // 着色器程序 ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); glLinkProgram(ID); checkCompileErrors(ID, "PROGRAM"); // 删除着色器,因为它们已经链接到我们的程序中了,不再需要 glDeleteShader(vertex); glDeleteShader(fragment); } // 激活着色器程序 void use() { glUseProgram(ID); } // 实用的uniform函数,用于在着色器程序中设置值 // 设置布尔类型的uniform void setBool(const std::string& name, bool value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); } // 设置整数类型的uniform void setInt(const std::string& name, int value) const { glUniform1i(glGetUniformLocation(ID, name.c_str()), value); } // 设置浮点类型的uniform void setFloat(const std::string& name, float value) const { glUniform1f(glGetUniformLocation(ID, name.c_str()), value); } // 设置vec2类型的uniform,使用glm::vec2 void setVec2(const std::string& name, const glm::vec2& value) const { glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } // 设置vec2类型的uniform,使用两个浮点数 void setVec2(const std::string& name, float x, float y) const { glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); } // 设置vec3类型的uniform,使用glm::vec3 void setVec3(const std::string& name, const glm::vec3& value) const { glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } // 设置vec3类型的uniform,使用三个浮点数 void setVec3(const std::string& name, float x, float y, float z) const { glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); } // 设置vec4类型的uniform,使用glm::vec4 void setVec4(const std::string& name, const glm::vec4& value) const { glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); } // 设置vec4类型的uniform,使用四个浮点数 void setVec4(const std::string& name, float x, float y, float z, float w) { glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); } // 设置mat2类型的uniform void setMat2(const std::string& name, const glm::mat2& mat) const { glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } // 设置mat3类型的uniform void setMat3(const std::string& name, const glm::mat3& mat) const { glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } // 设置mat4类型的uniform void setMat4(const std::string& name, const glm::mat4& mat) const { glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); } private: // 检查着色器编译/链接错误的实用函数 void checkCompileErrors(unsigned int shader, std::string type) { int success; char infoLog[1024]; if (type != "PROGRAM") { // 检查着色器编译错误 glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } else { // 检查程序链接错误 glGetProgramiv(shader, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shader, 1024, NULL, infoLog); std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl; } } } }; #endif ``` ### Camera 这是通用的摄像机类 ```c++ #ifndef CAMERA_H #define CAMERA_H #include #include #include #include // 为摄像机的移动定义了几种选项 enum Camera_Movement { FORWARD, BACKWARD, LEFT, RIGHT, UP, DOWN }; // 初始化摄像机变量的默认值 const float YAW = -90.0f; const float PITCH = 0.0f; const float SPEED = 2.5f; const float SENSITIVITY = 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(SENSITIVITY), 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(SENSITIVITY), Zoom(ZOOM) { Position = glm::vec3(posX, posY, posZ); WorldUp = glm::vec3(upX, upY, upZ); Yaw = yaw; Pitch = pitch; updateCameraVectors(); } // 返回计算出的视图矩阵,使用摄像机的欧拉角和 LookAt 矩阵 glm::mat4 GetViewMatrix() { return glm::lookAt(Position, Position + Front, Up); } // 处理从任何类似键盘的输入系统接收的输入,接受摄像机移动方向和时间增量 virtual 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; if (direction == UP) Position += Up * velocity; if (direction == DOWN) Position -= Up * velocity; } // 处理从鼠标输入系统接收的输入,计算x和y方向的偏移量 void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true) { xoffset *= MouseSensitivity; yoffset *= MouseSensitivity; Yaw += xoffset; Pitch += yoffset; // 确保当 Pitch 超出范围时,屏幕不会翻转 if (constrainPitch) { if (Pitch > 89.0f) Pitch = 89.0f; if (Pitch < -89.0f) Pitch = -89.0f; } // 使用更新的欧拉角更新摄像机向量 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; } protected: // 根据摄像机的最新欧拉角计算前向量 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)); } // 友元函数,用于重载 << 运算符 friend std::ostream& operator<<(std::ostream& os, const Camera& camera); }; // << 运算符重载函数 std::ostream& operator<<(std::ostream& os, const Camera& camera) { os << "Camera Position: (" << camera.Position.x << ", " << camera.Position.y << ", " << camera.Position.z << ")\n"; return os; } #endif ``` #### FollowCamera 继承父类的人物第三人称视角摄像机类 ```c++ #ifndef FOLLOWCAMERA_H #define FOLLOWCAMERA_H #include "planarCamera.h" // FollowCamera 类,继承自 PlanarCamera 类,实现摄像机跟随功能 class FollowCamera : public PlanarCamera { public: // 构造函数,初始化摄像机位置,默认位置为 (0.0f, 0.0f, 3.0f) FollowCamera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 3.0f)) : PlanarCamera(position) {} // 跟随目标位置,计算新的摄像机位置和方向 void Follow(glm::vec3 targetPosition, glm::vec3 frontProjection, glm::vec3 targetUp) { float followDistance = 4.0f; // 跟随距离 float followHeight = 2.0f; // 跟随高度 // 计算新的摄像机位置 glm::vec3 backOffset = -frontProjection * followDistance; glm::vec3 upOffset = glm::vec3(0.0f, followHeight, 0.0f); Position = targetPosition + backOffset + upOffset; // 计算新的摄像机前向量 glm::vec3 direction = glm::normalize(frontProjection); Front = direction; // 保持摄像机的上向量与目标摄像机一致 Up = targetUp; // 更新摄像机的向量 updateCameraVectors(); } }; #endif // FOLLOWCAMERA_H ``` #### PlanarCamera 继承父类的人物第一人称视角的摄像机类 ```c++ #ifndef PLANARCAMERA #define PLANARCAMERA #include "camera.h" #include "map.h" #include // PlanarCamera 类,继承自 Camera 类,实现平面内的摄像机运动和跳跃功能 class PlanarCamera : public Camera { public: bool isJumping = false; // 是否正在跳跃 float jumpVelocity = 0.6f; // 初始跳跃速度 float gravity = -9.8f; // 重力加速度 float groundY = -1.0f; // 地面的高度 float jumpHeight = 1.6f; // 跳跃高度 bool isSprinting = false; // 是否正在冲刺 float sprintMultiplier = 1.8f; // 冲刺速度倍增 // 构造函数,初始化摄像机位置和方向 PlanarCamera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Camera(position, glm::vec3(0.0f, 1.0f, 0.0f), yaw, pitch) { } // 处理键盘输入,重载自 Camera 类 void ProcessKeyboard(Camera_Movement direction, float deltaTime) override { float velocity = MovementSpeed * deltaTime; if (isSprinting) { velocity *= sprintMultiplier; } glm::vec3 frontProjection = glm::normalize(glm::vec3(Front.x, 0.0f, Front.z)); // 计算 Front 在 xz 平面上的投影 glm::vec3 newPosition = Position; if (direction == FORWARD) newPosition += frontProjection * velocity; if (direction == BACKWARD) newPosition -= frontProjection * velocity; if (direction == LEFT) newPosition -= Right * velocity; if (direction == RIGHT) newPosition += Right * velocity; // 在目标方向前进 1.0 单位后的新位置 glm::vec3 targetPosition = newPosition; if (direction == FORWARD) targetPosition += frontProjection * 1.0f; if (direction == BACKWARD) targetPosition -= frontProjection * 1.0f; if (direction == LEFT) targetPosition -= Right * 1.0f; if (direction == RIGHT) targetPosition += Right * 1.0f; // 碰撞检测:检查新目标位置的高度 float targetGroundY = GetHeightAtPosition(targetPosition.x, targetPosition.z); // 如果新的地面高度高于当前高度,并且不是在跳跃,阻止移动 if (!isJumping && targetGroundY > Position.y + 0.1f) { return; } // 更新位置和地面高度 Position = newPosition; groundY = GetHeightAtPosition(Position.x, Position.z); // 如果当前高度大于新的地面高度,并且没有在跳跃,则下落到新的地面高度 if (!isJumping && Position.y > groundY) { Position.y = groundY; } } // 处理跳跃逻辑 void Jump(float deltaTime) { if (isJumping) { Position.y += jumpVelocity * deltaTime; jumpVelocity += gravity * deltaTime; // 更新地面高度 groundY = GetHeightAtPosition(Position.x, Position.z); // 当位置低于地面高度时停止跳跃 if (Position.y <= groundY) { Position.y = groundY; isJumping = false; jumpVelocity = 1.2f; // 重置跳跃速度 } } } // 开始跳跃 void StartJump() { if (!isJumping) { isJumping = true; jumpVelocity = sqrt(2.0f * -gravity * jumpHeight); // 计算初始跳跃速度 } } // 开始冲刺 void StartSprint() { isSprinting = true; } // 停止冲刺 void StopSprint() { isSprinting = false; } // 更新摄像机状态 void Update(float deltaTime) { // 如果不在跳跃状态,自动下落 if (!isJumping) { float newGroundY = GetHeightAtPosition(Position.x, Position.z); if (Position.y > newGroundY) { Position.y -= 0.1 * gravity * deltaTime; // 下落速度可以用 gravity 控制 if (Position.y < newGroundY) { Position.y = newGroundY; } } } else { Jump(deltaTime); } } }; #endif // !PLANARCAMERA ``` ### Skybox 用于加载天空盒的代码头文件 ```c++ #ifndef SKYBOX_H #define SKYBOX_H #include #include #include #include #include "shader.h" extern unsigned int skyboxVAO; extern unsigned int skyboxVBO; extern std::vector cubemapTextures; extern float blendFactor ; extern bool transitioning ; extern float transitionSpeed ; // Adjust this value to control the speed of transition extern int currentSkyboxIndex ; extern int nextSkyboxIndex ; extern std::vector> allFaces; void renderSky(); #endif ``` ### Map 地图类,就来加载地图 ```c++ #ifndef MAP_H #define MAP_H #include #include #include #include #include // 假设地图的尺寸 const int MAP_WIDTH = 100; const int MAP_HEIGHT = 100; const int HIGHLAND_HEIGHT = 12; const int MAX_HEIGHT_DIFF = 4; // 除了高原边缘,其他区域高度差最大值 extern std::vector> highPoints; // 地图高度数据 extern std::vector> heightMap; // 获取给定位置的高度 float GetHeightAtPosition(float x, float z); //随机生成地图 //void GenerateHeightMap(const std::string& filename); void GenerateHeightMap(const std::string& filename, std::vector>& highPoints); // 从文件读取高度图 void LoadHeightMapFromFile(const std::string& filename); // 随机生成高度值,但限制相邻高度差 int GenerateRandomHeight(int currentHeight); // 自定义的 clamp 函数 template T clamp(T value, T min, T max) { if (value < min) return min; if (value > max) return max; return value; } #endif // MAP_H ``` ### Mesh 网格类,就来给model类使用 ```c++ #ifndef MESH_H #define MESH_H #include #include #include #include "shader.h" #include #include using namespace std; #define MAX_BONE_INFLUENCE 4 // 最大骨骼影响数量 // 顶点结构体,包含顶点的各种属性 struct Vertex { glm::vec3 Position; // 顶点位置 glm::vec3 Normal; // 法线向量 glm::vec2 TexCoords; // 纹理坐标 glm::vec3 Tangent; // 切线向量 glm::vec3 Bitangent; // 副切线向量 int m_BoneIDs[MAX_BONE_INFLUENCE]; // 骨骼ID float m_Weights[MAX_BONE_INFLUENCE]; // 骨骼权重 }; // 材质结构体,包含材质的各种属性 struct Material { glm::vec3 Diffuse; // 漫反射颜色 glm::vec3 Ambient; // 环境光颜色 glm::vec3 Specular; // 镜面反射颜色 float Shininess; // 光泽度 float Opacity; // 不透明度 }; // 网格类,包含顶点、索引和材质信息,并处理渲染 class Mesh { public: vector vertices; // 顶点数据 vector indices; // 索引数据 Material material; // 材质信息 unsigned int VAO; // 顶点数组对象 // 构造函数,初始化网格数据 Mesh(vector vertices, vector indices, Material material) { this->vertices = vertices; this->indices = indices; this->material = material; setupMesh(); } // 绘制网格 void Draw(Shader& shader) { // 设置材质属性 shader.setVec3("materialDiffuse", material.Diffuse); shader.setVec3("materialAmbient", material.Ambient); shader.setVec3("materialSpecular", material.Specular); shader.setFloat("materialShininess", material.Shininess); shader.setFloat("materialOpacity", material.Opacity); // 绑定 VAO 并绘制元素 glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, static_cast(indices.size()), GL_UNSIGNED_INT, 0); glBindVertexArray(0); } private: unsigned int VBO, EBO; // 顶点缓冲对象和索引缓冲对象 // 初始化网格数据,设置 VAO、VBO 和 EBO void setupMesh() { glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glGenBuffers(1, &EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); // 设置顶点属性指针 glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal)); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords)); glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Tangent)); glEnableVertexAttribArray(4); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Bitangent)); glEnableVertexAttribArray(5); glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, m_BoneIDs)); glEnableVertexAttribArray(6); glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_Weights)); glBindVertexArray(0); } }; #endif ``` ### Model 用于加载3D模型 ```c++ #ifndef MODEL_H #define MODEL_H #include #include #include #include #include #include #include "mesh.h" #include "shader.h" #include #include using namespace std; // 光源结构体 struct Light { glm::vec3 Position; // 光源位置 glm::vec3 Color; // 光源颜色 float Brightness; // 光源亮度 }; // 模型类,用于加载和绘制模型 class Model { public: vector meshes; // 网格数据 string directory; // 模型文件目录 bool gammaCorrection; // 是否启用伽马校正 vector lights; // 光源列表 glm::vec3 viewPos; // 观察者位置 // 构造函数,通过路径加载模型,并设置伽马校正选项 Model(string const& path, bool gamma = false) : gammaCorrection(gamma) { loadModel(path); } // 绘制模型,传入着色器 void Draw(Shader& shader) { // 设置光源属性 shader.setInt("numLights", lights.size()); for (unsigned int j = 0; j < lights.size(); j++) { shader.setVec3("lights[" + to_string(j) + "].Position", lights[j].Position); shader.setVec3("lights[" + to_string(j) + "].Color", lights[j].Color); shader.setFloat("lights[" + to_string(j) + "].Brightness", lights[j].Brightness); } shader.setVec3("viewPos", viewPos); // 绘制所有网格 for (unsigned int i = 0; i < meshes.size(); i++) { meshes[i].Draw(shader); } } private: // 从文件路径加载模型 void loadModel(string const& path) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(path, aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace); if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { cout << "ERROR::ASSIMP:: " << importer.GetErrorString() << endl; return; } directory = path.substr(0, path.find_last_of('/')); processNode(scene->mRootNode, scene); } // 递归处理节点 void processNode(aiNode* node, const aiScene* scene) { // 处理节点中的所有网格 for (unsigned int i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; meshes.push_back(processMesh(mesh, scene)); } // 递归处理子节点 for (unsigned int i = 0; i < node->mNumChildren; i++) { processNode(node->mChildren[i], scene); } } // 处理网格 Mesh processMesh(aiMesh* mesh, const aiScene* scene) { vector vertices; vector indices; Material material; // 处理顶点 for (unsigned int i = 0; i < mesh->mNumVertices; i++) { Vertex vertex; glm::vec3 vector; vector.x = mesh->mVertices[i].x; vector.y = mesh->mVertices[i].y; vector.z = mesh->mVertices[i].z; vertex.Position = vector; if (mesh->HasNormals()) { vector.x = mesh->mNormals[i].x; vector.y = mesh->mNormals[i].y; vector.z = mesh->mNormals[i].z; vertex.Normal = vector; } if (mesh->mTextureCoords[0]) { glm::vec2 vec; vec.x = mesh->mTextureCoords[0][i].x; vec.y = mesh->mTextureCoords[0][i].y; vertex.TexCoords = vec; vector.x = mesh->mTangents[i].x; vector.y = mesh->mTangents[i].y; vector.z = mesh->mTangents[i].z; vertex.Tangent = vector; vector.x = mesh->mBitangents[i].x; vector.y = mesh->mBitangents[i].y; vector.z = mesh->mBitangents[i].z; vertex.Bitangent = vector; } else vertex.TexCoords = glm::vec2(0.0f, 0.0f); vertices.push_back(vertex); } // 处理索引 for (unsigned int i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for (unsigned int j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } // 处理材质 if (mesh->mMaterialIndex >= 0) { aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex]; aiColor3D color(0.f, 0.f, 0.f); float shininess, opacity; mat->Get(AI_MATKEY_COLOR_DIFFUSE, color); material.Diffuse = glm::vec3(color.r, color.g, color.b); mat->Get(AI_MATKEY_COLOR_AMBIENT, color); material.Ambient = glm::vec3(color.r, color.g, color.b); mat->Get(AI_MATKEY_COLOR_SPECULAR, color); material.Specular = glm::vec3(color.r, color.g, color.b); mat->Get(AI_MATKEY_SHININESS, shininess); material.Shininess = shininess; mat->Get(AI_MATKEY_OPACITY, opacity); material.Opacity = opacity; } return Mesh(vertices, indices, material); } }; #endif ``` ### Struct 结构体设置 #### Particle 粒子设置,用于设置雨滴 ```c++ struct Particle { glm::vec3 Position; glm::vec3 Velocity; float Life; // 粒子的生命周期 }; ``` #### keyStatus 键状态,用户捕捉按键事件 ```c++ // 键状态记录 struct KeyState { bool W = false; bool A = false; bool S = false; bool D = false; bool R = false; bool G = false; bool B = false; bool O = false; bool P = false; bool U = false; bool I = false; bool J = false; bool K = false; bool L = false; }; ``` ### function 具体实现各种功能的方法 ```c++ // 当窗口大小改变时调用的回调函数 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 mouse_button_callback(GLFWwindow* window, int button, int action, int mods); // 当键盘按键按下或释放时调用的回调函数 void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); // 处理输入(键盘和鼠标)的函数 void processInput(GLFWwindow* window, glm::vec3 cameraPosition); // 加载纹理的函数,返回纹理ID unsigned int loadTexture(const char* path, bool gammaCorrection); // 加载立方体贴图(天空盒)的函数,返回立方体贴图的ID unsigned int loadCubemap(vector faces); // 加载多个立方体贴图的函数,返回包含多个立方体贴图ID的向量 std::vector loadCubemaps(const std::vector>& cubemapFaces); // 添加初始光源的函数 void addInitialLightSource(); // 设置着色器的uniform变量,传递光源信息 void setUniforms(Shader& shader, const std::vector& lights, int numLights); // 渲染四边形的函数 void renderQuad(); // 渲染立方体的函数 void renderCube(); // 渲染高度图的函数 void renderHeightMap(const glm::mat4& view, const glm::mat4& projection, Shader& shader, const std::vector& textures); // 渲染光源的函数 void renderLights(const std::vector& lights, Shader& shaderLight, void (*renderCube)()); // 更新键盘状态的函数 void updateKeyState(GLFWwindow* window, KeyState& keyState); // 在相机位置附近添加光源的函数 void addLight(std::vector& lights, const glm::vec3& cameraPosition); // 移除相机位置附近光源的函数 void removeLightsNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold); // 增加相机位置附近光源强度的函数 void increaseLightIntensityNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 减少相机位置附近光源强度的函数 void decreaseLightIntensityNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 渲染光源轮廓的函数 void renderLightOutlines(const std::vector& lights, const glm::vec3& cameraPosition, Shader& shaderOutline, void (*renderCube)()); // 增加相机位置附近光源红色分量的函数 void increaseLightRNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 减少相机位置附近光源红色分量的函数 void decreaseLightRNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 增加相机位置附近光源绿色分量的函数 void increaseLightGNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 减少相机位置附近光源绿色分量的函数 void decreaseLightGNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 增加相机位置附近光源蓝色分量的函数 void increaseLightBNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 减少相机位置附近光源蓝色分量的函数 void decreaseLightBNearCamera(std::vector& lights, const glm::vec3& cameraPosition, float threshold, float intensityIncrement); // 初始化粒子的函数 void initParticles(); // 更新粒子状态的函数 void updateParticles(float deltaTime); // 渲染椭圆形状的函数 void renderEllipse(); // 渲染雨滴效果的函数 void renderRain(Shader& shader, const glm::mat4& view, const glm::mat4& projection); // 渲染树模型的函数 void renderTrees(Model& treeModel, const glm::mat4& view, const glm::mat4& projection, Shader& shader, int numTrees ); // 渲染皮卡丘模型的函数 void renderPikachu(Model& model, const glm::mat4& view, const glm::mat4& projection, Shader& shader); // 渲染低多边形树模型的函数 void renderlowTrees(Model& treeModel, const glm::mat4& view, const glm::mat4& projection, Shader& shader, int numTrees); // 加载帧动画的函数 void loadWdssFrames(); // 渲染当前帧的函数 void renderCurrentFrame(const glm::mat4& view, const glm::mat4& projection, Shader& shader); ```