#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);
};
#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();
};
#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);
}
};
#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();
};
#define STB_IMAGE_IMPLEMENTATION
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
// 必须添加这两个头文件才能使用 std::this_thread 和 std::chrono
#include <thread>
#include <chrono>
// 包含你自己写的类
#include "Shader.h"
#include "Texture.h"
int main() {
// ======== 初始化 GLFW 和 OpenGL ==========
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, "Rendering Lab", nullptr, nullptr);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// 设置视口回调
glfwSetFramebufferSizeCallback(window, [](GLFWwindow*, int w, int h) {
glViewport(0, 0, w, h);
});
// ======== 初始化 GLAD ==========
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cerr << "Failed to initialize GLAD" << std::endl;
return -1;
}
// ======== SHADER ==========
Shader shader;
shader.use();
shader.setInt("texture1", 0); // 第一纹理单元
shader.setInt("texture2", 1); // 第二纹理单元(用于叠加)
// ✅ 不再需要那一行错误代码!
// ======== TEXTURES ==========
Texture tex1("resources/image1.jpg"); // 木板纹理
Texture tex2("resources/image2.jpg"); // 双木板
Texture tex3("resources/image3.png", true); // 白亮斑点(带alpha)
Texture tex4("resources/image4.png"); // 笑脸纹理
// ======== RECTANGLE VAO/VBO/EBO ==========
float rectVertices[] = {
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 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);
// ======== HEXAGON 六边形 ==========
const int N = 6;
std::vector<float> hexVertices;
std::vector<unsigned int> hexIndices;
// 中心点
hexVertices.push_back(0.0f); hexVertices.push_back(0.0f);
hexVertices.push_back(0.5f); hexVertices.push_back(0.5f); // UV
for (int i = 0; i < N; ++i) {
float angle = 2.0f * 3.1415926f * i / N;
float x = cos(angle), y = sin(angle);
hexVertices.push_back(x); hexVertices.push_back(y);
hexVertices.push_back((x + 1.0f) / 2.0f);
hexVertices.push_back((y + 1.0f) / 2.0f);
}
for (int i = 1; i <= N; ++i) {
hexIndices.push_back(0);
hexIndices.push_back(i);
hexIndices.push_back(i % N + 1);
}
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, hexVertices.size() * sizeof(float), hexVertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO_hex);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, hexIndices.size() * sizeof(unsigned int), hexIndices.data(), 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);
// ========== RENDER LOOP ==========
while (!glfwWindowShouldClose(window)) {
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shader.use();
// --- 第一帧:矩形 + image1 ---
tex1.bind(0);
glBindVertexArray(VAO_rect);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
std::this_thread::sleep_for(std::chrono::seconds(2));
// --- 第二帧:image2 + image3 叠加 ---
glClear(GL_COLOR_BUFFER_BIT);
tex2.bind(0); // 绑定到纹理单元0
tex3.bind(1); // 绑定到纹理单元1
shader.setFloat("blendAlpha", 0.6f); // 控制叠加强度
glBindVertexArray(VAO_rect);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
std::this_thread::sleep_for(std::chrono::seconds(2));
// --- 第三帧:六边形 + 笑脸 ---
glClear(GL_COLOR_BUFFER_BIT);
tex4.bind(0);
shader.setFloat("blendAlpha", 0.0f); // 关闭叠加
glBindVertexArray(VAO_hex);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(hexIndices.size()), GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
std::this_thread::sleep_for(std::chrono::seconds(2));
break; // 演示完退出(实际可用按键切换)
}
// 清理资源(可选)
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
#include "Shader.h"
#include <iostream>
// 定义静态成员变量(必须在类外定义)
std::string Shader::vertexSource = R"(
#version 330 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 330 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);
}
#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);
}
#include "Texture.h"
#include <iostream>
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) {
GLenum format = GL_RGB;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
else if (channels == 4)
format = GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
SOIL_free_image_data(data);
std::cout << "✅ SOIL2 成功加载: " << path << " (" << width << "x" << height << ")\n";
}
else {
std::cerr << "❌ SOIL2 无法加载图片: " << path << "\n";
std::cerr << "💡 错误码: " << SOIL_last_result() << "\n";
}
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture::bind(unsigned int unit) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, ID);
}
Texture::~Texture() {
glDeleteTextures(1, &ID);
}