又開始找工作了,借機休息出去旅行兩個月,順便利用這段時間整理下以前寫的東西。
以下是一個簡單的動態批處理實現:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>// 頂點結構體
struct Vertex {float x, y, z; // 位置float r, g, b; // 顏色
};// 動態批處理類
class DynamicBatch {
public:DynamicBatch() {// 初始化 VAO 和 VBOglGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);glBindVertexArray(VAO);glBindBuffer(GL_ARRAY_BUFFER, VBO);// 設置頂點屬性指針glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, x));glEnableVertexAttribArray(0);glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, r));glEnableVertexAttribArray(1);glBindVertexArray(0);}~DynamicBatch() {glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);}// 添加頂點數據void AddVertex(const Vertex& vertex) {vertices.push_back(vertex);}// 更新頂點緩沖區void UpdateBuffer() {glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_DYNAMIC_DRAW);}// 渲染批處理void Render() {glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, vertices.size());glBindVertexArray(0);}// 清空頂點數據void Clear() {vertices.clear();}private:GLuint VAO, VBO; // 頂點數組對象和頂點緩沖區對象std::vector<Vertex> vertices; // 頂點數據
};
// 頂點著色器
const char* vertexShaderSource = R"(
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
out vec3 ourColor;
void main() {gl_Position = vec4(aPos, 1.0);ourColor = aColor;
}
)";// 片段著色器
const char* fragmentShaderSource = R"(
#version 330 core
in vec3 ourColor;
out vec4 FragColor;
void main() {FragColor = vec4(ourColor, 1.0);
}
)";
// 編譯著色器
GLuint CompileShader(GLenum type, const char* source) {GLuint shader = glCreateShader(type);glShaderSource(shader, 1, &source, nullptr);glCompileShader(shader);GLint success;glGetShaderiv(shader, GL_COMPILE_STATUS, &success);if (!success) {char infoLog[512];glGetShaderInfoLog(shader, 512, nullptr, infoLog);std::cerr << "Shader compilation failed: " << infoLog << std::endl;}return shader;
}// 鏈接著色器程序
GLuint CreateShaderProgram(const char* vertexSource, const char* fragmentSource) {GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertexSource);GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentSource);GLuint shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);GLint success;glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);if (!success) {char infoLog[512];glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);std::cerr << "Shader program linking failed: " << infoLog << std::endl;}glDeleteShader(vertexShader);glDeleteShader(fragmentShader);return shaderProgram;
}int main() {// 初始化 GLFWif (!glfwInit()) {std::cerr << "Failed to initialize GLFW" << std::endl;return -1;}// 創建窗口GLFWwindow* window = glfwCreateWindow(800, 600, "Dynamic Batching Example", nullptr, nullptr);if (!window) {std::cerr << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);// 初始化 GLEWif (glewInit() != GLEW_OK) {std::cerr << "Failed to initialize GLEW" << std::endl;return -1;}// 創建著色器程序GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource);// 創建動態批處理對象DynamicBatch batch;// 主循環while (!glfwWindowShouldClose(window)) {glClear(GL_COLOR_BUFFER_BIT);// 添加頂點數據batch.Clear();batch.AddVertex({-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f});batch.AddVertex({0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f});batch.AddVertex({0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f});// 更新緩沖區并渲染batch.UpdateBuffer();glUseProgram(shaderProgram);batch.Render();// 交換緩沖區glfwSwapBuffers(window);glfwPollEvents();}// 清理glDeleteProgram(shaderProgram);glfwTerminate();return 0;
}
代碼說明
DynamicBatch 類:
負責管理頂點數據、更新頂點緩沖區和渲染。使用 std::vector 存儲動態頂點數據。
通過 glBufferData 將頂點數據上傳到 GPU。
頂點和片段著色器:簡單的著色器,用于渲染帶顏色的三角形。
主循環:每一幀清空批處理數據,添加新的頂點數據,更新緩沖區并渲染。
動態更新:使用 GL_DYNAMIC_DRAW 標志更新頂點緩沖區,適用于頻繁變化的頂點數據。
運行結果
運行程序后,你會看到一個彩色的三角形。每一幀都會動態更新頂點數據并渲染。
優化建議
減少內存分配:
如果頂點數據頻繁變化,可以預先分配足夠的內存,避免頻繁調用 glBufferData。
使用實例化渲染:
如果需要渲染大量相同對象,可以使用實例化渲染(Instanced Rendering)進一步優化性能。
多線程更新:
在多線程環境中,可以將頂點數據的更新和渲染分離到不同的線程中。
通過動態批處理,你可以有效地減少繪制調用,提高渲染性能,特別是在需要渲染大量小對象的場景中。