opengl-homework/main.cpp

693 lines
22 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// main.cpp
#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
#include <vector>
#include <cmath> // For sin, cos
// GLM Headers
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/constants.hpp> // 包含 glm::pi
#include "shader_utils.hpp" // 我们创建的着色器加载工具
// 窗口尺寸
int windowWidth = 1024;
int windowHeight = 768;
// 着色器程序ID
GLuint programID;
GLuint axesProgramID; // Shader program for axes
// GLuint pickingProgramID; // (可选,如果实现拾取)
// Uniform ID
GLuint MatrixID_MVP, MatrixID_M, MatrixID_V;
GLuint LightPosID, LightColorID, LightPowerID, ViewPosID;
GLuint TextureSamplerID;
GLuint AxesMatrixID_MVP; // MVP uniform for axes shader
// VAO 和 VBO
GLuint CubeVAO, CubeVBO_vertices, CubeVBO_normals, CubeVBO_uvs;
GLuint AxesVAO, AxesVBO_vertices, AxesVBO_colors;
// GLuint LightVAO; // 用于表示光源的球体 (使用 GLUT 绘制可能不需要单独VAO)
// 纹理
GLuint checkerboardTextureID;
// 相机参数
glm::vec3 cameraPosition = glm::vec3(3.0f, 3.0f, 3.0f);
float cameraHorizontalAngle = glm::pi<float>(); // 初始水平角 (pi)
float cameraVerticalAngle = 0.0f; // 初始垂直角
float initialFoV = 45.0f;
float cameraSpeed = 9.0f; // 单位/秒
float mouseSpeed = 0.002f;
// 鼠标状态
int lastMouseX = windowWidth / 2;
int lastMouseY = windowHeight / 2;
bool mouseLeftDown = false;
// 光源属性
glm::vec3 lightPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 lightColor = glm::vec3(1.0f, 1.0f, 1.0f);
float lightPower = 2.0f; // 修改光照强度
// 立方体旋转
float cubeRotationAngle = 0.0f;
// 函数声明
void initGL();
void display();
void reshape(int, int);
void keyboard(unsigned char, int, int);
void mouseButton(int button, int state, int x, int y);
void mouseMotion(int x, int y);
void idle();
void createGradientTexture();
void setupCubeBuffers();
void setupAxesBuffers(); // Added
void renderAxes(const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix); // Added
void renderText(const char* text, float x, float y, float r = 1.0f, float g = 1.0f, float b = 1.0f);
// 立方体顶点数据 (位置, 法线, UV)
const GLfloat cube_vertices[] = {
// Back face
-0.5f, -0.5f, -0.5f, // Bottom-left
0.5f, 0.5f, -0.5f, // top-right
0.5f, -0.5f, -0.5f, // bottom-right
0.5f, 0.5f, -0.5f, // top-right
-0.5f, -0.5f, -0.5f, // bottom-left
-0.5f, 0.5f, -0.5f, // top-left
// Front face
-0.5f, -0.5f, 0.5f, // bottom-left
0.5f, -0.5f, 0.5f, // bottom-right
0.5f, 0.5f, 0.5f, // top-right
0.5f, 0.5f, 0.5f, // top-right
-0.5f, 0.5f, 0.5f, // top-left
-0.5f, -0.5f, 0.5f, // bottom-left
// Left face
-0.5f, 0.5f, 0.5f, // top-right
-0.5f, 0.5f, -0.5f, // top-left
-0.5f, -0.5f, -0.5f, // bottom-left
-0.5f, -0.5f, -0.5f, // bottom-left
-0.5f, -0.5f, 0.5f, // bottom-right
-0.5f, 0.5f, 0.5f, // top-right
// Right face
0.5f, 0.5f, 0.5f, // top-left
0.5f, -0.5f, -0.5f, // bottom-right
0.5f, 0.5f, -0.5f, // top-right
0.5f, -0.5f, -0.5f, // bottom-right
0.5f, 0.5f, 0.5f, // top-left
0.5f, -0.5f, 0.5f, // bottom-left
// Bottom face
-0.5f, -0.5f, -0.5f, // top-right
0.5f, -0.5f, -0.5f, // top-left
0.5f, -0.5f, 0.5f, // bottom-left
0.5f, -0.5f, 0.5f, // bottom-left
-0.5f, -0.5f, 0.5f, // bottom-right
-0.5f, -0.5f, -0.5f, // top-right
// Top face
-0.5f, 0.5f, -0.5f, // top-left
-0.5f, 0.5f, 0.5f, // bottom-left
0.5f, 0.5f, 0.5f, // bottom-right
0.5f, 0.5f, 0.5f, // bottom-right
0.5f, 0.5f, -0.5f, // top-right
-0.5f, 0.5f, -0.5f, // top-left
};
// Axes vertex data
const GLfloat axes_vertices[] = {
// X-axis (red)
0.0f, 0.0f, 0.0f,
2.0f, 0.0f, 0.0f,
// Y-axis (green)
0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f,
// Z-axis (blue)
0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 2.0f
};
const GLfloat axes_colors[] = {
// X-axis (red)
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
// Y-axis (green)
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
// Z-axis (blue)
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f
};
const GLfloat cube_normals[] = {
// Back face
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f,
// Front face
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
// Left face
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f,
// Right face
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
// Bottom face
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
0.0f, -1.0f, 0.0f,
// Top face
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
const GLfloat cube_uvs[] = {
// Back face
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 0.0f,
0.0f, 1.0f,
// Front face
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
// Left face
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
// Right face
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
// Bottom face
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
// Top face
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
};
void createGradientTexture() {
const int texWidth = 128;
const int texHeight = 128;
GLubyte gradientTexture[texHeight][texWidth][3]; // RGB
for (int i = 0; i < texHeight; i++) {
for (int j = 0; j < texWidth; j++) {
// 创建漂亮的蓝紫色渐变
float u = (float)j / texWidth;
float v = (float)i / texHeight;
GLubyte r = (GLubyte)(180 + 75 * sin(u * 6.28));
GLubyte g = (GLubyte)(100 + 50 * sin(v * 6.28));
GLubyte b = (GLubyte)(200 + 55 * cos(u * v * 10));
gradientTexture[i][j][0] = r;
gradientTexture[i][j][1] = g;
gradientTexture[i][j][2] = b;
}
}
glGenTextures(1, &checkerboardTextureID);
glBindTexture(GL_TEXTURE_2D, checkerboardTextureID);
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_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, gradientTexture);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
void setupCubeBuffers() {
glGenVertexArrays(1, &CubeVAO);
glBindVertexArray(CubeVAO);
// 顶点位置
glGenBuffers(1, &CubeVBO_vertices);
glBindBuffer(GL_ARRAY_BUFFER, CubeVBO_vertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices), cube_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
// 法线
glGenBuffers(1, &CubeVBO_normals);
glBindBuffer(GL_ARRAY_BUFFER, CubeVBO_normals);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_normals), cube_normals, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
// UV坐标
glGenBuffers(1, &CubeVBO_uvs);
glBindBuffer(GL_ARRAY_BUFFER, CubeVBO_uvs);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_uvs), cube_uvs, GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(2);
// 解绑VAO
glBindVertexArray(0);
}
void setupAxesBuffers() {
glGenVertexArrays(1, &AxesVAO);
glBindVertexArray(AxesVAO);
// Vertex positions
glGenBuffers(1, &AxesVBO_vertices);
glBindBuffer(GL_ARRAY_BUFFER, AxesVBO_vertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(axes_vertices), axes_vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
// Vertex colors
glGenBuffers(1, &AxesVBO_colors);
glBindBuffer(GL_ARRAY_BUFFER, AxesVBO_colors);
glBufferData(GL_ARRAY_BUFFER, sizeof(axes_colors), axes_colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
void initGL() {
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW" << std::endl;
exit(-1);
}
std::cout << "Using GLEW Version: " << glewGetString(GLEW_VERSION) << std::endl;
std::cout << "OpenGL Renderer: " << glGetString(GL_RENDERER) << std::endl;
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
std::cout << "GLSL Version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
// 修改清除颜色为浅灰色,这样如果渲染失败更容易看出来
glClearColor(0.8f, 0.8f, 0.8f, 1.0f);
// 确保深度测试正确设置
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
// 禁用背面剔除,这样我们可以看到立方体的所有面
glDisable(GL_CULL_FACE);
programID = LoadShaders("shaders/phong.vert", "shaders/phong.frag");
if (programID == 0) {
std::cerr << "Failed to load shaders. Exiting." << std::endl;
exit(-1);
}
axesProgramID = LoadShaders("shaders/axes.vert", "shaders/axes.frag");
if (axesProgramID == 0) {
std::cerr << "Failed to load axes shaders. Exiting." << std::endl;
exit(-1);
}
// 添加着色器编译状态检查
GLint success;
GLchar infoLog[512];
glGetProgramiv(programID, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(programID, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// 检查uniform变量位置
MatrixID_MVP = glGetUniformLocation(programID, "MVP");
if (MatrixID_MVP == -1) std::cerr << "MVP uniform not found" << std::endl;
MatrixID_M = glGetUniformLocation(programID, "M");
if (MatrixID_M == -1) std::cerr << "M uniform not found" << std::endl;
MatrixID_V = glGetUniformLocation(programID, "V");
if (MatrixID_V == -1) std::cerr << "V uniform not found" << std::endl;
LightPosID = glGetUniformLocation(programID, "lightPos_worldspace");
if (LightPosID == -1) std::cerr << "lightPos_worldspace uniform not found" << std::endl;
LightColorID = glGetUniformLocation(programID, "lightColor");
if (LightColorID == -1) std::cerr << "lightColor uniform not found" << std::endl;
LightPowerID = glGetUniformLocation(programID, "lightPower");
if (LightPowerID == -1) std::cerr << "lightPower uniform not found" << std::endl;
ViewPosID = glGetUniformLocation(programID, "viewPos");
if (ViewPosID == -1) std::cerr << "viewPos uniform not found" << std::endl;
TextureSamplerID = glGetUniformLocation(programID, "myTextureSampler");
if (TextureSamplerID == -1) std::cerr << "myTextureSampler uniform not found" << std::endl;
AxesMatrixID_MVP = glGetUniformLocation(axesProgramID, "MVP");
if (AxesMatrixID_MVP == -1) std::cerr << "Axes MVP uniform not found" << std::endl;
createGradientTexture();
setupCubeBuffers();
setupAxesBuffers();
glutSetCursor(GLUT_CURSOR_NONE);
glutWarpPointer(windowWidth / 2, windowHeight / 2);
lastMouseX = windowWidth / 2;
lastMouseY = windowHeight / 2;
}
void renderText(const char* text, float x, float y, float r, float g, float b) {
glUseProgram(0); // 禁用着色器
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, windowWidth, 0, windowHeight);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_DEPTH_TEST); // 禁用深度测试以便文字总是在前面
glColor3f(r, g, b);
glRasterPos2f(x, y);
for (const char* c = text; *c != '\0'; c++) {
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, *c);
}
glEnable(GL_DEPTH_TEST); // 恢复深度测试
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
void renderAxes(const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix) {
glUseProgram(axesProgramID);
glm::mat4 ModelMatrixAxes = glm::mat4(1.0); // Identity matrix, axes at origin
glm::mat4 MVP_Axes = projectionMatrix * viewMatrix * ModelMatrixAxes;
if (AxesMatrixID_MVP != -1) {
glUniformMatrix4fv(AxesMatrixID_MVP, 1, GL_FALSE, &MVP_Axes[0][0]);
}
glBindVertexArray(AxesVAO);
glLineWidth(2.0f); // Make axes lines thicker
glDrawArrays(GL_LINES, 0, 6); // 3 lines, 2 vertices each
glBindVertexArray(0);
glLineWidth(1.0f); // Reset line width
}
void display() {
// 检查OpenGL错误
GLenum err;
while((err = glGetError()) != GL_NO_ERROR) {
std::cerr << "OpenGL error before rendering: " << err << std::endl;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 检查深度测试状态
GLboolean depthTestEnabled;
glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
if (!depthTestEnabled) {
std::cerr << "深度测试未启用" << std::endl;
}
glm::vec3 direction(
cos(cameraVerticalAngle) * sin(cameraHorizontalAngle),
sin(cameraVerticalAngle),
cos(cameraVerticalAngle) * cos(cameraHorizontalAngle)
);
glm::vec3 right = glm::vec3(
sin(cameraHorizontalAngle - glm::pi<float>()/2.0f),
0,
cos(cameraHorizontalAngle - glm::pi<float>()/2.0f)
);
glm::vec3 up = glm::cross(right, direction);
glm::mat4 ProjectionMatrix = glm::perspective(glm::radians(initialFoV), (float)windowWidth / (float)windowHeight, 0.1f, 100.0f);
glm::mat4 ViewMatrix = glm::lookAt(
cameraPosition,
glm::vec3(0.0f, 0.0f, 0.0f), // 看向原点
up
);
// Render Cube
glUseProgram(programID); // Ensure correct shader is used for the cube
glm::mat4 ModelMatrixCube = glm::mat4(1.0);
ModelMatrixCube = glm::translate(ModelMatrixCube, glm::vec3(0.0f, 0.0f, 0.0f));
ModelMatrixCube = glm::rotate(ModelMatrixCube, cubeRotationAngle, glm::vec3(0.0f, 1.0f, 0.0f));
ModelMatrixCube = glm::scale(ModelMatrixCube, glm::vec3(1.0f, 1.0f, 1.0f));
glm::mat4 MVP_Cube = ProjectionMatrix * ViewMatrix * ModelMatrixCube;
// 设置uniform变量
if (MatrixID_MVP != -1) {
glUniformMatrix4fv(MatrixID_MVP, 1, GL_FALSE, &MVP_Cube[0][0]);
}
if (MatrixID_M != -1) {
glUniformMatrix4fv(MatrixID_M, 1, GL_FALSE, &ModelMatrixCube[0][0]);
}
if (MatrixID_V != -1) {
glUniformMatrix4fv(MatrixID_V, 1, GL_FALSE, &ViewMatrix[0][0]);
}
if (LightPosID != -1) {
glUniform3fv(LightPosID, 1, &lightPos[0]);
}
if (LightColorID != -1) {
glUniform3fv(LightColorID, 1, &lightColor[0]);
}
if (LightPowerID != -1) {
glUniform1f(LightPowerID, lightPower);
}
if (ViewPosID != -1) {
glUniform3fv(ViewPosID, 1, &cameraPosition[0]);
}
// 检查纹理绑定状态
GLint textureBound;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, checkerboardTextureID);
if (TextureSamplerID != -1) {
glUniform1i(TextureSamplerID, 0);
}
glGetIntegerv(GL_TEXTURE_BINDING_2D, &textureBound);
if (textureBound != checkerboardTextureID) {
std::cerr << "纹理未正确绑定" << std::endl;
}
// 先绑定VAO
glBindVertexArray(CubeVAO);
// 检查VAO绑定状态
GLint vaoBound;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vaoBound);
if (vaoBound != CubeVAO) {
std::cerr << "VAO未正确绑定" << std::endl;
return;
}
// 绘制
glDrawArrays(GL_TRIANGLES, 0, 36);
// 解绑VAO
glBindVertexArray(0);
// Render Axes
renderAxes(ProjectionMatrix, ViewMatrix);
// 检查绘制后的OpenGL错误
while((err = glGetError()) != GL_NO_ERROR) {
std::cerr << "OpenGL error after rendering: " << err << std::endl;
}
// 绘制光源 (使用 GLUT 绘制一个白色小球)
glUseProgram(0);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(glm::value_ptr(ProjectionMatrix));
glMatrixMode(GL_MODELVIEW);
glm::mat4 MV_Light = ViewMatrix * glm::translate(glm::mat4(1.0f), lightPos) * glm::scale(glm::mat4(1.0f), glm::vec3(0.1f));
glLoadMatrixf(glm::value_ptr(MV_Light));
glColor3f(lightColor.r, lightColor.g, lightColor.b);
glutSolidSphere(0.1, 10, 10);
// 渲染操作说明文字
renderText("Controls:", 10, windowHeight - 20, 1.0f, 1.0f, 0.0f);
renderText("W/S: Move Forward/Backward", 10, windowHeight - 40);
renderText("A/D: Strafe Left/Right", 10, windowHeight - 60);
renderText("Space/C: Move Up/Down", 10, windowHeight - 80);
renderText("Left Mouse Drag: Rotate View", 10, windowHeight - 100);
renderText("ESC: Exit Program", 10, windowHeight - 120);
glutSwapBuffers();
}
void reshape(int w, int h) {
windowWidth = w;
windowHeight = h;
if (h == 0) h = 1;
glViewport(0, 0, w, h);
glutPostRedisplay();
}
void keyboard(unsigned char key, int x, int y) {
float deltaTime = 0.016f; // 假设大约60FPS, 更精确的delta time计算会更好
glm::vec3 direction(
cos(cameraVerticalAngle) * sin(cameraHorizontalAngle),
sin(cameraVerticalAngle),
cos(cameraVerticalAngle) * cos(cameraHorizontalAngle)
);
glm::vec3 right = glm::vec3(
sin(cameraHorizontalAngle - glm::pi<float>()/2.0f),
0,
cos(cameraHorizontalAngle - glm::pi<float>()/2.0f)
);
switch (key) {
case 'w': case 'W': cameraPosition += direction * deltaTime * cameraSpeed; break;
case 's': case 'S': cameraPosition -= direction * deltaTime * cameraSpeed; break;
case 'a': case 'A': cameraPosition -= right * deltaTime * cameraSpeed; break;
case 'd': case 'D': cameraPosition += right * deltaTime * cameraSpeed; break;
case ' ': cameraPosition.y += deltaTime * cameraSpeed; break; // 空格键向上
case 'c': case 'C': cameraPosition.y -= deltaTime * cameraSpeed; break; // C键向下
case 27: // ESC 键
glDeleteBuffers(1, &CubeVBO_vertices);
glDeleteBuffers(1, &CubeVBO_normals);
glDeleteBuffers(1, &CubeVBO_uvs);
glDeleteVertexArrays(1, &CubeVAO);
glDeleteProgram(programID);
glDeleteTextures(1, &checkerboardTextureID);
// Cleanup for axes
glDeleteBuffers(1, &AxesVBO_vertices);
glDeleteBuffers(1, &AxesVBO_colors);
glDeleteVertexArrays(1, &AxesVAO);
glDeleteProgram(axesProgramID);
exit(0);
break;
}
glutPostRedisplay();
}
void mouseButton(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
mouseLeftDown = true;
lastMouseX = x;
lastMouseY = y;
} else if (state == GLUT_UP) {
mouseLeftDown = false;
}
}
}
void mouseMotion(int x, int y) {
// 仅当鼠标在窗口内时处理,避免跳动
if (x < 0 || x >= windowWidth || y < 0 || y >= windowHeight) {
// 当鼠标移出窗口时,可以选择不更新视角或者将鼠标重置回中心
// 如果选择重置,可能需要更复杂的逻辑来避免在窗口边缘的抖动
// mouseLeftDown = false; // 取消注释此行可以在鼠标移出时停止拖动视角
return;
}
if (mouseLeftDown) {
float deltaX = float(x - lastMouseX);
float deltaY = float(y - lastMouseY);
cameraHorizontalAngle += mouseSpeed * deltaX;
cameraVerticalAngle += mouseSpeed * deltaY;
// 限制垂直角度
cameraVerticalAngle = glm::clamp(cameraVerticalAngle, -glm::pi<float>()/2.0f + 0.01f, glm::pi<float>()/2.0f - 0.01f);
lastMouseX = x;
lastMouseY = y;
// FPS游戏风格的鼠标控制 (可选):
// if (x != windowWidth/2 || y != windowHeight/2) {
// glutWarpPointer(windowWidth/2, windowHeight/2);
// lastMouseX = windowWidth/2;
// lastMouseY = windowHeight/2;
// }
glutPostRedisplay();
}
}
void idle() {
cubeRotationAngle += 0.005f;
if (cubeRotationAngle > 2.0f * glm::pi<float>()) {
cubeRotationAngle -= 2.0f * glm::pi<float>();
}
glutPostRedisplay();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(windowWidth, windowHeight);
glutInitWindowPosition(100, 100);
glutCreateWindow("OpenGL Course Project - 3D Scene");
initGL();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouseButton);
glutMotionFunc(mouseMotion);
// glutPassiveMotionFunc(mouseMotion); // 如果希望鼠标不按下也触发 warp (如果使用)
glutIdleFunc(idle);
glutMainLoop();
return 0;
}