#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <glad/stb_image.h> // 仅用于加载纹理,轻量级库
#include <iostream>
#include <cmath>
#define _USE_MATH_DEFINES
// 窗口设置
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// 全局状态
enum ShadingModel { FLAT, GOURAUD, PHONG };
ShadingModel currentShading = PHONG;
bool isTextured = true;
float rotX = 0.0f, rotY = 0.0f; // 旋转角度
float scaleFactor = 1.0f; // 缩放因子
float translateX = 0.0f, translateY = 0.0f; // 平移
bool firstMouse = true;
float lastX = SCR_WIDTH / 2.0f;
float lastY = SCR_HEIGHT / 2.0f;
float cameraZ = 3.0f; // 相机Z轴位置(控制缩放)
// 基础矩阵运算(替代glm)
struct Mat4 {
float m[4][4] = {0};
Mat4() {
// 单位矩阵
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
}
};
// 矩阵乘法
Mat4 multiplyMat4(const Mat4& a, const Mat4& b) {
Mat4 res;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
res.m[i][j] = 0;
for (int k = 0; k < 4; k++) {
res.m[i][j] += a.m[i][k] * b.m[k][j];
}
}
}
return res;
}
// 平移矩阵
Mat4 translate(float x, float y, float z) {
Mat4 res;
res.m[3][0] = x;
res.m[3][1] = y;
res.m[3][2] = z;
return res;
}
// X轴旋转矩阵
Mat4 rotateX(float rad) {
Mat4 res;
res.m[1][1] = cos(rad);
res.m[1][2] = -sin(rad);
res.m[2][1] = sin(rad);
res.m[2][2] = cos(rad);
return res;
}
// Y轴旋转矩阵
Mat4 rotateY(float rad) {
Mat4 res;
res.m[0][0] = cos(rad);
res.m[0][2] = sin(rad);
res.m[2][0] = -sin(rad);
res.m[2][2] = cos(rad);
return res;
}
// 缩放矩阵
Mat4 scale(float x, float y, float z) {
Mat4 res;
res.m[0][0] = x;
res.m[1][1] = y;
res.m[2][2] = z;
return res;
}
// 透视投影矩阵
Mat4 perspective(float fovRad, float aspect, float near, float far) {
Mat4 res;
float tanHalfFov = tan(fovRad / 2.0f);
res.m[0][0] = 1.0f / (aspect * tanHalfFov);
res.m[1][1] = 1.0f / tanHalfFov;
res.m[2][2] = -(far + near) / (far - near);
res.m[2][3] = -1.0f;
res.m[3][2] = -(2.0f * far * near) / (far - near);
res.m[3][3] = 0.0f;
return res;
}
// 着色器源码
const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform int shadingModel;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoord;
out vec3 GouraudColor;
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
uniform vec3 viewPos;
vec3 calculateLighting(vec3 normal, vec3 fragPos) {
vec3 ambient = light.ambient;
vec3 lightDir = normalize(light.position - fragPos);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff;
vec3 viewDir = normalize(viewPos - fragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = light.specular * spec;
return ambient + diffuse + specular;
}
void main() {
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal;
TexCoord = aTexCoord;
gl_Position = projection * view * vec4(FragPos, 1.0);
if (shadingModel == 1) { // Gouraud着色
GouraudColor = calculateLighting(Normal, FragPos);
}
}
)";
const char* fragmentShaderSource = R"(
#version 330 core
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoord;
in vec3 GouraudColor;
uniform int shadingModel;
uniform bool isTextured;
uniform sampler2D texture1;
uniform vec3 objectColor;
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light light;
uniform vec3 viewPos;
vec3 calculateLighting(vec3 normal, vec3 fragPos) {
vec3 ambient = light.ambient;
vec3 lightDir = normalize(light.position - fragPos);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff;
vec3 viewDir = normalize(viewPos - fragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = light.specular * spec;
return ambient + diffuse + specular;
}
void main() {
vec3 color = isTextured ? texture(texture1, TexCoord).rgb : objectColor;
if (shadingModel == 0) { // 平面着色
vec3 normal = normalize(Normal);
gl_FragColor = vec4(color * calculateLighting(normal, FragPos), 1.0);
} else if (shadingModel == 1) { // Gouraud着色
gl_FragColor = vec4(color * GouraudColor, 1.0);
} else { // Phong着色
vec3 normal = normalize(Normal);
gl_FragColor = vec4(color * calculateLighting(normal, FragPos), 1.0);
}
}
)";
// 回调函数
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
glViewport(0, 0, width, height);
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
if (firstMouse) {
lastX = xpos;
lastY = ypos;
firstMouse = false;
return;
}
float xoffset = xpos - lastX;
float yoffset = lastY - ypos; // Y轴反向
lastX = xpos;
lastY = ypos;
// 右键旋转
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {
rotY += xoffset * 0.1f;
rotX += yoffset * 0.1f;
}
// 中键平移
else if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS) {
translateX += xoffset * 0.005f;
translateY -= yoffset * 0.005f;
}
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
cameraZ = std::max(1.0f, std::min(cameraZ - yoffset * 0.2f, 10.0f)); // 滚轮控制相机距离
}
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
// 数字键1-3切换着色模型
if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS) currentShading = FLAT;
if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS) currentShading = GOURAUD;
if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS) currentShading = PHONG;
// T键切换纹理
if (glfwGetKey(window, GLFW_KEY_T) == GLFW_PRESS) isTextured = !isTextured;
// 鼠标左键缩放物体
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {
scale *= (1.0f + yoffset * 0.1f);
scale = std::max(0.1f, std::min(scale, 5.0f));
}
}
// 加载纹理(仅使用stb_image,不依赖其他库)
unsigned int loadTexture(const char* path) {
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true); // 翻转纹理Y轴
unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0);
if (data) {
GLenum format = (nrChannels == 4) ? GL_RGBA : GL_RGB;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// 设置纹理过滤和环绕方式
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_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
std::cout << "Failed to load texture: " << path << std::endl;
}
stbi_image_free(data);
return textureID;
}
// 编译着色器工具函数
unsigned int compileShader(unsigned int type, const char* source) {
unsigned int shader = glCreateShader(type);
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
// 检查错误
int success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, NULL, infoLog);
std::cout << "Shader compilation error:\n" << infoLog << std::endl;
}
return shader;
}
int main() {
// 初始化GLFW
glfwInit();
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, "OpenGL Demo (Only GLAD+GLFW)", NULL, NULL);
if (!window) {
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
// 初始化GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// 启用深度测试
glEnable(GL_DEPTH_TEST);
// 编译着色器
unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// 立方体顶点数据(位置、法向量、纹理坐标)
float vertices[] = {
// 前后面
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
// 左右面
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
// 上下底面
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
// 创建VAO、VBO
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);
// 顶点属性:位置(0)、法向量(1)、纹理坐标(2)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
// 加载纹理(准备一张名为texture.jpg的图片放在同级目录)
unsigned int texture = loadTexture("texture.jpg");
glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "texture1"), 0);
// 设置光照参数
glUniform3f(glGetUniformLocation(shaderProgram, "light.position"), 1.2f, 1.0f, 2.0f);
glUniform3f(glGetUniformLocation(shaderProgram, "light.ambient"), 0.2f, 0.2f, 0.2f);
glUniform3f(glGetUniformLocation(shaderProgram, "light.diffuse"), 0.8f, 0.8f, 0.8f);
glUniform3f(glGetUniformLocation(shaderProgram, "light.specular"), 1.0f, 1.0f, 1.0f);
glUniform3f(glGetUniformLocation(shaderProgram, "objectColor"), 0.8f, 0.5f, 0.2f);
glUniform3f(glGetUniformLocation(shaderProgram, "viewPos"), 0.0f, 0.0f, cameraZ);
// 渲染循环
while (!glfwWindowShouldClose(window)) {
processInput(window);
// 清空缓冲
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 使用着色器
glUseProgram(shaderProgram);
// 计算模型矩阵(平移→旋转→缩放)
Mat4 model = translate(translateX, translateY, 0.0f);
Mat4 rotX = rotateX(rotateX * M_PI / 180.0f);
Mat4 rotY = rotateY(rotateY * M_PI / 180.0f);
model = multiplyMat4(model, rotY);
model = multiplyMat4(model, rotX);
model = multiplyMat4(model, scale(scale, scale, scale));
// 计算视图矩阵(相机沿Z轴移动)
Mat4 view = translate(0.0f, 0.0f, -cameraZ);
// 计算投影矩阵
float aspect = (float)SCR_WIDTH / SCR_HEIGHT;
Mat4 projection = perspective(45.0f * M_PI / 180.0f, aspect, 0.1f, 100.0f);
// 传递矩阵到着色器
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, &model.m[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, &view.m[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, &projection.m[0][0]);
// 更新着色模型和纹理状态
glUniform1i(glGetUniformLocation(shaderProgram, "shadingModel"), currentShading);
glUniform1i(glGetUniformLocation(shaderProgram, "isTextured"), isTextured);
// 绑定纹理并绘制
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 36);
// 交换缓冲和事件
glfwSwapBuffers(window);
glfwPollEvents();
}
// 清理资源
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
glfwTerminate();
return 0;
}
最新发布