685 lines
21 KiB
C++
685 lines
21 KiB
C++
#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;
|
||
}
|