OpenGL与现代GPU架构:技术教程_2024-07-20_12-06-07.Tex

OpenGL与现代GPU架构:技术教程

OpenGL基础

OpenGL的历史与发展

OpenGL,全称为Open Graphics Library,是一个跨语言、跨平台的应用程序接口(API)用于渲染2D和3D矢量图形。它最初由Silicon Graphics Inc.(SGI)在1992年开发,旨在为图形编程提供一个开放标准,替代了当时专有的图形API。随着时间的推移,OpenGL不断演进,吸纳了新的图形硬件特性,如纹理映射、顶点着色器、片段着色器等,以适应现代GPU架构的复杂性和高性能需求。

OpenGL的核心概念

OpenGL的核心概念包括:

  • 上下文(Context):OpenGL的渲染状态和功能集存储在上下文中,每个上下文可以独立于其他上下文运行。
  • 缓冲区(Buffer):用于存储顶点数据、纹理数据等,如顶点缓冲区(VBO)、纹理缓冲区(TBO)等。
  • 顶点着色器(Vertex Shader):在GPU上运行的程序,用于处理顶点数据,如位置、颜色、纹理坐标等。
  • 片段着色器(Fragment Shader):也称为像素着色器,用于处理每个像素的最终颜色。
  • 纹理(Texture):用于映射到3D模型上的图像,增加真实感。
#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类图,分析框架结构,绘制框架类图,要放在文档里,要那种简易图,大家都看的懂的,专业的
10-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值