685 lines
21 KiB
C++
Raw Permalink 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.

#include <GL/glew.h>
#include <GL/glut.h>
#include <iostream>
#include <vector>
#include <cmath>
// GLM Headers
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "shader_utils.hpp" // 着色器加载工具
// 窗口尺寸
int windowWidth = 1024;
int windowHeight = 768;
// 着色器程序ID
GLuint programID;
GLuint axesProgramID;
// Uniform ID
GLuint MatrixID_MVP, MatrixID_M, MatrixID_V;
GLuint LightPosID, LightColorID, LightPowerID, ViewPosID;
GLuint TextureSamplerID;
GLuint AxesMatrixID_MVP;
// VAO 和 VBO
GLuint CubeVAO, CubeVBO_vertices, CubeVBO_normals, CubeVBO_uvs;
GLuint AxesVAO, AxesVBO_vertices, AxesVBO_colors;
// 纹理
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();
void renderAxes(const glm::mat4& projectionMatrix, const glm::mat4& viewMatrix);
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 << "初始化 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. QWQ" << std::endl;
exit(-1);
}
axesProgramID = LoadShaders("shaders/axes.vert", "shaders/axes.frag");
if (axesProgramID == 0) {
std::cerr << "Failed to load axes shaders. QWQ" << 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);
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);
glDrawArrays(GL_LINES, 0, 6);
glBindVertexArray(0);
glLineWidth(1.0f);
}
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
);
glUseProgram(programID);
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);
// 画坐标轴
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);
// 渲染操作说明文字emmm看来不能非ASCII
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);
// 删除坐标轴相关资源
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) {
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);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}