#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>
#include "Shader.h"
#include "Texture.h"
int main() {
// ========== 初始化 GLFW ==========
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr);
if (!window) {
std::cerr << "创建窗口失败!" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// ========== 初始化 GLAD ==========
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cerr << "初始化 GLAD 失败!" << std::endl;
return -1;
}
// ========== 设置视口 ==========
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, [](GLFWwindow*, int w, int h) {
glViewport(0, 0, w, h);
});
// ========== 创建着色器和纹理 ==========
Shader shader; // 着色器(自动编译内联代码)
Texture tex1("resources/image1.jpg"); // 木板纹理
Texture tex2("resources/image2.jpg"); // 第二块木板
Texture tex3("resources/image3.png", true); // 白亮斑点(带透明度)
Texture tex4("resources/image4.png"); // 笑脸纹理
// ========== 场景1:矩形(用于前两个画面)==========
float rectVertices[] = {
// 位置(x,y) 纹理(u,v)
0.5f, 0.5f, 1.0f, 1.0f, // 右上
0.5f, -0.5f, 1.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 1.0f // 左上
};
unsigned int rectIndices[] = { 0, 1, 3, 1, 2, 3 };
unsigned int VAO_rect, VBO_rect, EBO_rect;
glGenVertexArrays(1, &VAO_rect);
glGenBuffers(1, &VBO_rect);
glGenBuffers(1, &EBO_rect);
glBindVertexArray(VAO_rect);
glBindBuffer(GL_ARRAY_BUFFER, VBO_rect);
glBufferData(GL_ARRAY_BUFFER, sizeof(rectVertices), rectVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_rect);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(rectIndices), rectIndices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
// ========== 场景2:六边形(笑脸中间部分)==========
// 手动写出6个点的位置和纹理坐标(新手友好)
float hexVertices[] = {
// 位置 纹理坐标(全部指向图片中间)
0.0f, 0.8f, 0.5f, 0.6f, // 上
0.7f, 0.4f, 0.6f, 0.55f, // 右上
0.7f, -0.4f, 0.6f, 0.45f, // 右下
0.0f, -0.8f, 0.5f, 0.4f, // 下
-0.7f, -0.4f, 0.4f, 0.45f, // 左下
-0.7f, 0.4f, 0.4f, 0.55f, // 左上
};
// 索引:用6个三角形组成一个六边形面(围绕中心?但我们不用中心点)
// 改成用两个大三角形拼出六边形轮廓(简化)
unsigned int hexIndices[] = {
0, 1, 5, // 上半部分
1, 2, 5, // 右侧
2, 3, 4, // 下半部分
4, 5, 2 // 左侧连接
};
unsigned int VAO_hex, VBO_hex, EBO_hex;
glGenVertexArrays(1, &VAO_hex);
glGenBuffers(1, &VBO_hex);
glGenBuffers(1, &EBO_hex);
glBindVertexArray(VAO_hex);
glBindBuffer(GL_ARRAY_BUFFER, VBO_hex);
glBufferData(GL_ARRAY_BUFFER, sizeof(hexVertices), hexVertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_hex);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(hexIndices), hexIndices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
// ========== 主循环 ==========
int scene = 0; // 当前画面:0=木板, 1=叠加, 2=笑脸六边形
while (!glfwWindowShouldClose(window)) {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shader.use(); // 使用内置着色器
if (scene == 0) {
// 显示第一张木板
tex1.bind(0);
shader.setInt("texture1", 0);
shader.setInt("texture2", 1);
shader.setFloat("blendAlpha", 0.0f);
glBindVertexArray(VAO_rect);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
else if (scene == 1) {
// 显示两张纹理叠加
tex2.bind(0);
tex3.bind(1);
shader.setInt("texture1", 0);
shader.setInt("texture2", 1);
shader.setFloat("blendAlpha", 0.6f);
glBindVertexArray(VAO_rect);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}
else {
// 显示六边形,只贴笑脸中间部分
tex4.bind(0);
shader.setInt("texture1", 0);
shader.setInt("texture2", 1);
shader.setFloat("blendAlpha", 0.0f);
glBindVertexArray(VAO_hex);
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0); // 12个索引
}
glfwSwapBuffers(window);
glfwPollEvents();
// 按空格切换场景
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
scene = (scene + 1) % 3;
std::this_thread::sleep_for(std::chrono::milliseconds(300)); // 防止连按
}
}
return 0;
}
#pragma once
#include <string>
#include <SOIL2/SOIL2.h>
#include <glad/glad.h>
class Texture {
public:
unsigned int ID;
std::string path;
Texture(const std::string& imagePath, bool alpha = false);
void bind(unsigned int unit = 0); // texture unit like GL_TEXTURE0
~Texture();
};
#include "Texture.h"
#include <iostream>
#include <cstring> // for std::memcpy or manual flip
// 构造函数:从文件路径创建纹理
Texture::Texture(const std::string& imagePath, bool alpha) : path(imagePath) {
glGenTextures(1, &ID);
glBindTexture(GL_TEXTURE_2D, ID);
// 设置纹理环绕方式
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);
// 加载图像数据
int width, height, channels;
unsigned char* data = SOIL_load_image(path.c_str(), &width, &height, &channels, SOIL_LOAD_AUTO);
if (!data) {
std::cerr << "❌ SOIL2 无法加载图片: " << path << "\n";
std::cerr << "💡 错误码: " << SOIL_last_result() << "\n";
return;
}
std::cout << "✅ 成功加载: " << path << " (" << width << "x" << height << ")\n";
// 👇 关键步骤:在上传到 OpenGL 前,先垂直翻转图像数据
int row_size = width * channels;
unsigned char* temp_row = new unsigned char[row_size];
for (int y = 0; y < height / 2; y++) {
unsigned char* row_top = data + y * row_size;
unsigned char* row_bottom = data + (height - 1 - y) * row_size;
std::memcpy(temp_row, row_top, row_size);
std::memcpy(row_top, row_bottom, row_size);
std::memcpy(row_bottom, temp_row, row_size);
}
delete[] temp_row;
// 判断格式
GLenum format = GL_RGB;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
else if (channels == 4)
format = GL_RGBA;
// 上传纹理到 GPU
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// 释放 CPU 端图像数据
SOIL_free_image_data(data);
// 解绑纹理
glBindTexture(GL_TEXTURE_2D, 0);
}
// 绑定纹理到指定纹理单元
void Texture::bind(unsigned int unit) {
if (unit >= 32) return; // OpenGL 最多支持 32 个纹理单元
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, ID);
}
// 析构函数:释放纹理资源
Texture::~Texture() {
glDeleteTextures(1, &ID);
}
#pragma once
#pragma once
#include <vector>
#include <glm/glm.hpp>
class Shape {
protected:
unsigned int VAO, VBO;
std::vector<float> vertices;
std::vector<unsigned int> indices;
public:
virtual void setup() = 0;
void draw();
virtual ~Shape();
};
#include "Shape.h"
#include <glad/glad.h>
void Shape::draw() {
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, 0);
}
Shape::~Shape() {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
}
#pragma once
#include <string>
#include <glad/glad.h>
class Shader {
public:
unsigned int ID;
// 构造函数(创建着色器用)
Shader();
// 使用这个着色器
void use();
// 设置 uniform 变量的值
void setInt(const std::string& name, int value);
void setFloat(const std::string& name, float value);
private:
// 这两个是字符串,保存你的顶点和片段着色器代码
static std::string vertexSource;
static std::string fragmentSource;
// 这是一个私有函数,用来编译单个着色器(比如顶点或片段)
unsigned int compileShader(unsigned int type, const std::string& source);
};
#include "Shader.h"
#include <iostream>
// 定义静态成员变量(必须在类外定义)
std::string Shader::vertexSource = R"(
#version 460 core
layout(location = 0) in vec2 aPos;
layout(location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main() {
gl_Position = vec4(aPos, 0.0, 1.0);
TexCoord = aTexCoord;
}
)";
std::string Shader::fragmentSource = R"(
#version 460 core
in vec2 TexCoord;
uniform sampler2D texture1;
uniform sampler2D texture2;
uniform float blendAlpha;
out vec4 FragColor;
void main() {
vec4 col1 = texture(texture1, TexCoord);
vec4 col2 = texture(texture2, TexCoord);
if (blendAlpha > 0.0) {
FragColor = mix(col1, col2, blendAlpha * col2.a);
} else {
FragColor = col1;
}
}
)";
// 编译单个着色器
unsigned int Shader::compileShader(unsigned int type, const std::string& source) {
unsigned int shader = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
int success;
char infoLog[512];
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 512, NULL, infoLog);
std::cout << "Shader Compile Error:\n" << infoLog << std::endl;
}
return shader;
}
// 构造函数
Shader::Shader() {
unsigned int vertex = compileShader(GL_VERTEX_SHADER, vertexSource);
unsigned int fragment = compileShader(GL_FRAGMENT_SHADER, fragmentSource);
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
int success;
char infoLog[512];
glGetProgramiv(ID, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(ID, 512, NULL, infoLog);
std::cerr << "Linking Shader Program Failed:\n" << infoLog << std::endl;
}
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void Shader::use() {
glUseProgram(ID);
}
void Shader::setInt(const std::string& name, int value) {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
void Shader::setFloat(const std::string& name, float value) {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
#pragma once
// 先包含 GLAD 和 OpenGL
#include <glad/glad.h>
// 包含 GLM 数学库
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> // 必须加!否则 value_ptr 找不到
// 包含你自己的类(顺序很重要)
#include "Shader.h" // 提供 Shader 类
#include "Texture.h" // 提供 Texture 类
class Sprite {
private:
unsigned int VAO, VBO;
public:
Sprite() {
float vertices[] = {
// 位置 // 纹理坐标
0.5f, 0.5f, 1.0f, 1.0f, // 右上
0.5f, -0.5f, 1.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 1.0f // 左上
};
unsigned int indices[] = {
0, 1, 3,
1, 2, 3
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 属性 0: 位置
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 属性 1: 纹理坐标
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
// 绘制精灵
void draw(float x, float y, float scale, Texture& tex, Shader& shader) {
// 激活并绑定纹理
glActiveTexture(GL_TEXTURE0);
tex.bind();
// 构建模型矩阵
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(x, y, 0.0f));
model = glm::scale(model, glm::vec3(scale));
// 使用着色器并传入 uniform
shader.use();
glUniformMatrix4fv(
glGetUniformLocation(shader.ID, "model"),
1, GL_FALSE,
glm::value_ptr(model)
);
glUniform1i(glGetUniformLocation(shader.ID, "texture1"), 0);
// 绘制
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
};
画出UML类图,分析框架结构,绘制框架类图,要放在文档里,要那种简易图,大家都看的懂的,专业的