雏形
#include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <iostream> #include <vector> #include <string> // 窗口尺寸 const unsigned int SCR_WIDTH = 1280; const unsigned int SCR_HEIGHT = 720; // 菜单栏常量 const int MENU_HEIGHT = 30; const int MENU_ITEM_WIDTH = 100; // 相机参数 glm::vec3 cameraPos = glm::vec3(0.0f, 50.0f, 150.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); float yaw = -90.0f; // 偏航角 float pitch = 0.0f; // 俯仰角 float fov = 75.0f; // 视野角 bool firstMouse = true; float lastX = SCR_WIDTH / 2.0f; float lastY = SCR_HEIGHT / 2.0f; float deltaTime = 0.0f; float lastFrame = 0.0f; bool mousePressed = false; bool isDragging = false; glm::vec2 dragStart; // 菜单状态 enum MenuItem { MENU_NONE, MENU_FILE, MENU_VIEW, MENU_HELP }; enum FileSubmenu { FILE_NONE, FILE_NEW, FILE_EXIT }; enum ViewSubmenu { VIEW_NONE, VIEW_RESET_CAMERA, VIEW_WIREFRAME, VIEW_SOLID }; MenuItem activeMenu = MENU_NONE; FileSubmenu activeFileSubmenu = FILE_NONE; ViewSubmenu activeViewSubmenu = VIEW_NONE; bool wireframeMode = false; // 物体选择相关 enum SelectedObject { SELECT_NONE, SELECT_DAM, SELECT_WATER, SELECT_MOUNTAIN }; SelectedObject selectedObject = SELECT_NONE; std::string objectInfo = "未选择任何物体"; // 鼠标回调函数 void mouseCallback(GLFWwindow* window, double xpos, double ypos) { // 检查是否在菜单栏区域 if (ypos < MENU_HEIGHT) { // 处理菜单鼠标移动 int x = static_cast<int>(xpos); int y = static_cast<int>(ypos); if (mousePressed) { // 处理菜单点击 if (x < MENU_ITEM_WIDTH) { activeMenu = MENU_FILE; activeViewSubmenu = VIEW_NONE; } else if (x < 2 * MENU_ITEM_WIDTH) { activeMenu = MENU_VIEW; activeFileSubmenu = FILE_NONE; } else if (x < 3 * MENU_ITEM_WIDTH) { activeMenu = MENU_HELP; activeFileSubmenu = FILE_NONE; activeViewSubmenu = VIEW_NONE; } else { activeMenu = MENU_NONE; activeFileSubmenu = FILE_NONE; activeViewSubmenu = VIEW_NONE; } } return; } // 处理3D场景鼠标交互 if (firstMouse) { lastX = xpos; lastY = ypos; firstMouse = false; } if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) { if (!isDragging) { isDragging = true; dragStart = glm::vec2(xpos, ypos); } else { float xoffset = xpos - lastX; float yoffset = lastY - ypos; lastX = xpos; lastY = ypos; float sensitivity = 0.1f; xoffset *= sensitivity; yoffset *= sensitivity; yaw += xoffset; pitch += yoffset; 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); } } else { if (isDragging) { isDragging = false; // 检测点击选择(简化版) glm::vec2 dragEnd(xpos, ypos); if (glm::length(dragEnd - dragStart) < 5.0f) { // 这里使用简单的位置判断模拟射线检测 float clickX = (2.0f * xpos) / SCR_WIDTH - 1.0f; float clickY = 1.0f - (2.0f * ypos) / SCR_HEIGHT; // 简化的物体选择逻辑 if (clickY > -0.5f && clickY < 0.5f && clickX > -0.3f && clickX < 0.3f) { selectedObject = SELECT_DAM; objectInfo = "大坝: 混凝土结构,高度50米"; } else if (clickY < -0.2f && clickX > -0.6f && clickX < 0.6f) { selectedObject = SELECT_WATER; objectInfo = "水体: 库容约500万立方米"; } else if ((clickX < -0.5f || clickX > 0.5f) && clickY < 0.3f) { selectedObject = SELECT_MOUNTAIN; objectInfo = "山体: 岩石结构,高度80米"; } else { selectedObject = SELECT_NONE; objectInfo = "未选择任何物体"; } } } firstMouse = true; } } // 鼠标按钮回调 void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { if (button == GLFW_MOUSE_BUTTON_LEFT) { if (action == GLFW_PRESS) { mousePressed = true; } else if (action == GLFW_RELEASE) { mousePressed = false; // 检查子菜单点击 double xpos, ypos; glfwGetCursorPos(window, &xpos, &ypos); int x = static_cast<int>(xpos); int y = static_cast<int>(ypos); if (activeMenu == MENU_FILE && y > MENU_HEIGHT && y < MENU_HEIGHT + 30 * 2) { if (x < MENU_ITEM_WIDTH) { if (y < MENU_HEIGHT + 30) { activeFileSubmenu = FILE_NEW; // 重置场景 cameraPos = glm::vec3(0.0f, 50.0f, 150.0f); cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); yaw = -90.0f; pitch = 0.0f; fov = 75.0f; selectedObject = SELECT_NONE; objectInfo = "未选择任何物体"; } else { activeFileSubmenu = FILE_EXIT; glfwSetWindowShouldClose(window, true); } } } else if (activeMenu == MENU_VIEW && y > MENU_HEIGHT && y < MENU_HEIGHT + 30 * 3) { if (x < MENU_ITEM_WIDTH) { if (y < MENU_HEIGHT + 30) { activeViewSubmenu = VIEW_RESET_CAMERA; cameraPos = glm::vec3(0.0f, 50.0f, 150.0f); cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); yaw = -90.0f; pitch = 0.0f; fov = 75.0f; } else if (y < MENU_HEIGHT + 60) { activeViewSubmenu = VIEW_WIREFRAME; wireframeMode = true; glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); } else { activeViewSubmenu = VIEW_SOLID; wireframeMode = false; glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } } // 点击其他区域关闭菜单 if (y > MENU_HEIGHT + 30 || x > MENU_ITEM_WIDTH * (activeMenu == MENU_FILE ? 1 : 1)) { activeMenu = MENU_NONE; activeFileSubmenu = FILE_NONE; activeViewSubmenu = VIEW_NONE; } } } } // 滚轮回调函数 void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { fov -= (float)yoffset; if (fov < 1.0f) fov = 1.0f; if (fov > 120.0f) fov = 120.0f; } // 处理键盘输入 void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); float cameraSpeed = 2.5f * 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; if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) cameraPos += cameraSpeed * cameraUp; if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) cameraPos -= cameraSpeed * cameraUp; } // 编译着色器 unsigned int compileShader(unsigned int type, const char* source) { unsigned int id = glCreateShader(type); glShaderSource(id, 1, &source, nullptr); glCompileShader(id); int result; glGetShaderiv(id, GL_COMPILE_STATUS, &result); if (result == GL_FALSE) { int length; glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length); char* message = (char*)alloca(length * sizeof(char)); glGetShaderInfoLog(id, length, &length, message); std::cout << "Failed to compile " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl; std::cout << message << std::endl; glDeleteShader(id); return 0; } return id; } // 创建着色器程序 unsigned int createShaderProgram(const char* vertexSource, const char* fragmentSource) { unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource); unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource); unsigned int program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); glLinkProgram(program); int result; glGetProgramiv(program, GL_LINK_STATUS, &result); if (result == GL_FALSE) { int length; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); char* message = (char*)alloca(length * sizeof(char)); glGetProgramInfoLog(program, length, &length, message); std::cout << "Failed to link shader program!" << std::endl; std::cout << message << std::endl; glDeleteProgram(program); return 0; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); return program; } // 创建立方体 unsigned int createCube(float width, float height, float depth, const glm::vec3& color) { float w = width / 2.0f; float h = height / 2.0f; float d = depth / 2.0f; float vertices[] = { // 位置 // 颜色 -w, -h, -d, color.r, color.g, color.b, w, -h, -d, color.r, color.g, color.b, w, h, -d, color.r, color.g, color.b, w, h, -d, color.r, color.g, color.b, -w, h, -d, color.r, color.g, color.b, -w, -h, -d, color.r, color.g, color.b, -w, -h, d, color.r, color.g, color.b, w, -h, d, color.r, color.g, color.b, w, h, d, color.r, color.g, color.b, w, h, d, color.r, color.g, color.b, -w, h, d, color.r, color.g, color.b, -w, -h, d, color.r, color.g, color.b, -w, h, d, color.r, color.g, color.b, -w, h, -d, color.r, color.g, color.b, -w, -h, -d, color.r, color.g, color.b, -w, -h, -d, color.r, color.g, color.b, -w, -h, d, color.r, color.g, color.b, -w, h, d, color.r, color.g, color.b, w, h, d, color.r, color.g, color.b, w, h, -d, color.r, color.g, color.b, w, -h, -d, color.r, color.g, color.b, w, -h, -d, color.r, color.g, color.b, w, -h, d, color.r, color.g, color.b, w, h, d, color.r, color.g, color.b, -w, -h, -d, color.r, color.g, color.b, w, -h, -d, color.r, color.g, color.b, w, -h, d, color.r, color.g, color.b, w, -h, d, color.r, color.g, color.b, -w, -h, d, color.r, color.g, color.b, -w, -h, -d, color.r, color.g, color.b, -w, h, -d, color.r, color.g, color.b, w, h, -d, color.r, color.g, color.b, w, h, d, color.r, color.g, color.b, w, h, d, color.r, color.g, color.b, -w, h, d, color.r, color.g, color.b, -w, h, -d, color.r, color.g, color.b }; unsigned int VAO, VBO; 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); return VAO; } // 创建平面 unsigned int createPlane(float width, float height, const glm::vec3& color) { float w = width / 2.0f; float h = height / 2.0f; float vertices[] = { // 位置 // 颜色 -w, 0.0f, -h, color.r, color.g, color.b, w, 0.0f, -h, color.r, color.g, color.b, w, 0.0f, h, color.r, color.g, color.b, w, 0.0f, h, color.r, color.g, color.b, -w, 0.0f, h, color.r, color.g, color.b, -w, 0.0f, -h, color.r, color.g, color.b }; unsigned int VAO, VBO; 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); return VAO; } // 创建锥体(简化版山体) unsigned int createCone(float radius, float height, int segments, const glm::vec3& color) { std::vector<float> vertices; // 底部中心 vertices.insert(vertices.end(), {0.0f, 0.0f, 0.0f, color.r, color.g, color.b}); // 底部边缘 for (int i = 0; i < segments; i++) { float angle = 2.0f * glm::pi<float>() * (float)i / (float)segments; float x = radius * cos(angle); float z = radius * sin(angle); vertices.insert(vertices.end(), {x, 0.0f, z, color.r, color.g, color.b}); } // 顶部点 vertices.insert(vertices.end(), {0.0f, height, 0.0f, color.r, color.g, color.b}); // 底部三角形 for (int i = 0; i < segments; i++) { int next = (i + 1) % segments; vertices.insert(vertices.end(), { 0.0f, 0.0f, 0.0f, color.r, color.g, color.b, radius * cos(2.0f * glm::pi<float>() * (float)next / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)next / (float)segments), color.r, color.g, color.b, radius * cos(2.0f * glm::pi<float>() * (float)i / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)i / (float)segments), color.r, color.g, color.b }); } // 侧面三角形 for (int i = 0; i < segments; i++) { int next = (i + 1) % segments; vertices.insert(vertices.end(), { 0.0f, height, 0.0f, color.r, color.g, color.b, radius * cos(2.0f * glm::pi<float>() * (float)i / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)i / (float)segments), color.r, color.g, color.b, radius * cos(2.0f * glm::pi<float>() * (float)next / (float)segments), 0.0f, radius * sin(2.0f * glm::pi<float>() * (float)next / (float)segments), color.r, color.g, color.b }); } unsigned int VAO, VBO; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), 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); return VAO; } // 渲染2D矩形(用于菜单) void renderRect(float x, float y, float width, float height, const glm::vec3& color, unsigned int shaderProgram) { float vertices[] = { x, y, 0.0f, color.r, color.g, color.b, x + width, y, 0.0f, color.r, color.g, color.b, x + width, y + height, 0.0f, color.r, color.g, color.b, x + width, y + height, 0.0f, color.r, color.g, color.b, x, y + height, 0.0f, color.r, color.g, color.b, x, y, 0.0f, color.r, color.g, color.b }; unsigned int VAO, VBO; 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); glDrawArrays(GL_TRIANGLES, 0, 6); glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); } // 渲染菜单 void renderMenu(unsigned int shaderProgram) { // 保存当前矩阵状态 glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, SCR_WIDTH, SCR_HEIGHT, 0, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); // 禁用深度测试以正确显示UI glDisable(GL_DEPTH_TEST); // 渲染主菜单条 renderRect(0, 0, SCR_WIDTH, MENU_HEIGHT, glm::vec3(0.3f, 0.3f, 0.3f), shaderProgram); // 渲染菜单项 renderRect(0, 0, MENU_ITEM_WIDTH, MENU_HEIGHT, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram); renderRect(MENU_ITEM_WIDTH, 0, MENU_ITEM_WIDTH, MENU_HEIGHT, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram); renderRect(2 * MENU_ITEM_WIDTH, 0, MENU_ITEM_WIDTH, MENU_HEIGHT, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram); // 恢复着色器程序的模型矩阵 glm::mat4 model = glm::mat4(1.0f); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glm::mat4 view = glm::mat4(1.0f); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view)); glm::mat4 projection = glm::ortho(0.0f, (float)SCR_WIDTH, (float)SCR_HEIGHT, 0.0f, -1.0f, 1.0f); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); // 渲染文件子菜单 if (activeMenu == MENU_FILE) { renderRect(0, MENU_HEIGHT, MENU_ITEM_WIDTH, 60, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram); renderRect(0, MENU_HEIGHT, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram); renderRect(0, MENU_HEIGHT + 30, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram); } // 渲染视图子菜单 if (activeMenu == MENU_VIEW) { renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT, MENU_ITEM_WIDTH, 90, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram); renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram); renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT + 30, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram); renderRect(MENU_ITEM_WIDTH, MENU_HEIGHT + 60, MENU_ITEM_WIDTH, 30, glm::vec3(0.5f, 0.5f, 0.5f), shaderProgram); } // 渲染帮助子菜单 if (activeMenu == MENU_HELP) { renderRect(2 * MENU_ITEM_WIDTH, MENU_HEIGHT, MENU_ITEM_WIDTH, 30, glm::vec3(0.4f, 0.4f, 0.4f), shaderProgram); } // 渲染物体信息面板 renderRect(SCR_WIDTH - 300, MENU_HEIGHT, 300, 30, glm::vec3(0.2f, 0.2f, 0.2f), shaderProgram); // 恢复深度测试 glEnable(GL_DEPTH_TEST); // 恢复矩阵状态 glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } int main() { // 初始化GLFW if (!glfwInit()) { std::cerr << "Failed to initialize GLFW" << std::endl; return -1; } // 设置OpenGL版本 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 创建窗口 GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "大坝3D模型", NULL, NULL); if (!window) { std::cerr << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); // 设置回调函数 glfwSetCursorPosCallback(window, mouseCallback); glfwSetMouseButtonCallback(window, mouseButtonCallback); glfwSetScrollCallback(window, scrollCallback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); // 初始化GLEW if (glewInit() != GLEW_OK) { std::cerr << "Failed to initialize GLEW" << std::endl; return -1; } // 启用深度测试 glEnable(GL_DEPTH_TEST); // 启用混合(用于半透明效果) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 顶点着色器代码 const char* vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 aPos;\n" "layout (location = 1) in vec3 aColor;\n" "out vec3 ourColor;\n" "uniform mat4 model;\n" "uniform mat4 view;\n" "uniform mat4 projection;\n" "void main()\n" "{\n" " gl_Position = projection * view * model * vec4(aPos, 1.0);\n" " ourColor = aColor;\n" "}\0"; // 片段着色器代码 const char* fragmentShaderSource = "#version 330 core\n" "in vec3 ourColor;\n" "out vec4 FragColor;\n" "void main()\n" "{\n" " FragColor = vec4(ourColor, 1.0);\n" "}\0"; // 创建着色器程序 unsigned int shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource); if (!shaderProgram) return -1; // 创建场景元素 // 地面 unsigned int groundVAO = createPlane(500, 500, glm::vec3(0.545f, 0.271f, 0.075f)); // 棕色 // 水体 unsigned int waterVAO = createPlane(300, 200, glm::vec3(0.275f, 0.509f, 0.706f)); // 钢蓝色 // 左侧山体 unsigned int leftMountainVAO = createCone(100, 80, 4, glm::vec3(0.133f, 0.545f, 0.133f)); // 绿色 // 右侧山体 unsigned int rightMountainVAO = createCone(100, 70, 4, glm::vec3(0.133f, 0.545f, 0.133f)); // 绿色 // 远处山体 unsigned int farMountainVAO = createCone(135, 50, 4, glm::vec3(0.133f, 0.4f, 0.133f)); // 深绿色 // 大坝基础 unsigned int damBaseVAO = createCube(100, 20, 40, glm::vec3(0.533f, 0.533f, 0.533f)); // 灰色 // 大坝正面倾斜部分 unsigned int damSlopeVAO = createCube(100, 30, 20, glm::vec3(0.533f, 0.533f, 0.533f)); // 灰色 // 坝顶结构 unsigned int damTopVAO = createCube(100, 5, 10, glm::vec3(0.533f, 0.533f, 0.533f)); // 灰色 // 水闸塔(使用浅灰色) glm::vec3 towerColor = glm::vec3(0.8f, 0.8f, 0.8f); unsigned int leftTower1VAO = createCube(6, 20, 10, towerColor); unsigned int leftTower2VAO = createCube(6, 20, 10, towerColor); unsigned int centerTower1VAO = createCube(6, 25, 10, towerColor); unsigned int centerTower2VAO = createCube(6, 25, 10, towerColor); unsigned int rightTower1VAO = createCube(6, 20, 10, towerColor); unsigned int rightTower2VAO = createCube(6, 20, 10, towerColor); // 右侧建筑 unsigned int rightBuildingVAO = createCube(15, 15, 10, towerColor); // 渲染循环 while (!glfwWindowShouldClose(window)) { // 计算时间差 float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // 处理输入 processInput(window); // 清空颜色缓冲和深度缓冲 glClearColor(0.533f, 0.808f, 0.922f, 1.0f); // 天空蓝 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 使用着色器程序 glUseProgram(shaderProgram); // 视图矩阵 glm::mat4 view = glm::lookAt(cameraPos, cameraPos + cameraFront, cameraUp); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view)); // 投影矩阵 glm::mat4 projection = glm::perspective(glm::radians(fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 2000.0f); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); // 绘制地面 glm::mat4 model = glm::mat4(1.0f); model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(groundVAO); glDrawArrays(GL_TRIANGLES, 0, 6); // 绘制远处山体 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(0, 0, -200)); model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); model = glm::rotate(model, glm::radians(180.0f), glm::vec3(0.0f, 1.0f, 0.0f)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(farMountainVAO); glDrawArrays(GL_TRIANGLES, 0, 4*3 + 4*3); // 底部4个三角形 + 侧面4个三角形 // 绘制左侧山体 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(-150, 20, -50)); model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); model = glm::rotate(model, glm::radians(45.0f), glm::vec3(0.0f, 1.0f, 0.0f)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(leftMountainVAO); glDrawArrays(GL_TRIANGLES, 0, 4*3 + 4*3); // 绘制右侧山体 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(150, 15, -50)); model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); model = glm::rotate(model, glm::radians(-45.0f), glm::vec3(0.0f, 1.0f, 0.0f)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(rightMountainVAO); glDrawArrays(GL_TRIANGLES, 0, 4*3 + 4*3); // 绘制水体(半透明) model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(0, 5, -100)); model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(waterVAO); glDrawArrays(GL_TRIANGLES, 0, 6); // 绘制大坝基础 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(0, 10, 0)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(damBaseVAO); glDrawArrays(GL_TRIANGLES, 0, 36); // 绘制大坝倾斜部分 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(0, 25, -10)); model = glm::rotate(model, glm::radians(-17.19f), glm::vec3(1.0f, 0.0f, 0.0f)); // -0.3弧度 ≈ -17.19度 glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(damSlopeVAO); glDrawArrays(GL_TRIANGLES, 0, 36); // 绘制坝顶结构 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(0, 30, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(damTopVAO); glDrawArrays(GL_TRIANGLES, 0, 36); // 绘制水闸塔 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(-30, 40, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(leftTower1VAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(-15, 40, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(leftTower2VAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(-5, 45, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(centerTower1VAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(5, 45, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(centerTower2VAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(15, 40, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(rightTower1VAO); glDrawArrays(GL_TRIANGLES, 0, 36); model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(30, 40, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(rightTower2VAO); glDrawArrays(GL_TRIANGLES, 0, 36); // 绘制右侧建筑 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(55, 35, 20)); glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(rightBuildingVAO); glDrawArrays(GL_TRIANGLES, 0, 36); // 渲染菜单 renderMenu(shaderProgram); // 交换缓冲并轮询事件 glfwSwapBuffers(window); glfwPollEvents(); } // 清理资源 glDeleteVertexArrays(1, &groundVAO); glDeleteVertexArrays(1, &waterVAO); glDeleteVertexArrays(1, &leftMountainVAO); glDeleteVertexArrays(1, &rightMountainVAO); glDeleteVertexArrays(1, &farMountainVAO); glDeleteVertexArrays(1, &damBaseVAO); glDeleteVertexArrays(1, &damSlopeVAO); glDeleteVertexArrays(1, &damTopVAO); glDeleteVertexArrays(1, &leftTower1VAO); glDeleteVertexArrays(1, &leftTower2VAO); glDeleteVertexArrays(1, ¢erTower1VAO); glDeleteVertexArrays(1, ¢erTower2VAO); glDeleteVertexArrays(1, &rightTower1VAO); glDeleteVertexArrays(1, &rightTower2VAO); glDeleteVertexArrays(1, &rightBuildingVAO); glDeleteProgram(shaderProgram); // 终止GLFW glfwTerminate(); return 0; }