以下是一个完整的OpenGL程序示例,演示了如何进行离屏渲染并将渲染结果显示在屏幕上。
并非在帧缓冲绑定的纹理上。
这个示例包括了创建窗口、初始化OpenGL、编译着色器、设置帧缓冲、绘制场景、以及交换缓冲等步骤。
代码注释详细解释了每个步骤的作用和原理。
教程:
下面详细解释了程序中的各个部分以及涉及的OpenGL概念:
-
初始化窗口和OpenGL上下文: 通过GLFW库创建一个窗口,并设置OpenGL版本及配置。
-
初始化GLEW: 初始化GLEW库以访问OpenGL函数。
-
设置顶点数据和顶点着色器: 创建一个三角形的顶点数据,并创建相应的顶点缓冲对象和顶点数组对象。编写顶点着色器来处理顶点数据的传递。
-
编译着色器程序: 编译顶点和片段着色器,并将它们链接到一个着色器程序中。
-
设置帧缓冲: 创建一个帧缓冲对象,并将一个纹理附件附加到帧缓冲中。这个纹理附件用来保存离屏渲染的结果。
-
渲染循环: 在每次循环中,清除颜色缓冲区,进行离屏渲染,然后将渲染结果显示在屏幕上。在离屏渲染时,将帧缓冲对象绑定为当前渲染目标,并在上屏渲染时将其绑定回默认的帧缓冲对象。
-
释放资源: 释放所有创建的OpenGL对象和程序。
通过理解这个示例程序,你可以学到如何使用帧缓冲对象进行离屏渲染,以及如何将离屏渲染的结果显示在屏幕上。
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>void framebuffer_size_callback(GLFWwindow* window, int width, int height) {glViewport(0, 0, width, height);
}int main() {// 初始化GLFWglfwInit();glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);// 创建窗口GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL", nullptr, nullptr);if (window == nullptr) {std::cerr << "Failed to create GLFW window" << std::endl;glfwTerminate();return -1;}glfwMakeContextCurrent(window);glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);// 初始化GLEWglewExperimental = GL_TRUE;if (glewInit() != GLEW_OK) {std::cerr << "Failed to initialize GLEW" << std::endl;return -1;}// 设置顶点数据和顶点着色器float vertices[] = {-0.5f, -0.5f, 0.0f, // 左下角0.5f, -0.5f, 0.0f, // 右下角0.0f, 0.5f, 0.0f // 顶部中心};unsigned int VBO, VAO;glGenVertexArrays(1, &VAO);glGenBuffers(1, &VBO);// 绑定VAOglBindVertexArray(VAO);// 绑定VBO并设置顶点数据glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);// 设置顶点属性指针glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);// 解绑VBO和VAOglBindBuffer(GL_ARRAY_BUFFER, 0);glBindVertexArray(0);// 编译着色器const char* vertexShaderSource = "#version 330 core\n""layout (location = 0) in vec3 aPos;\n""void main()\n""{\n"" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n""}\0";const char* fragmentShaderSource = "#version 330 core\n""out vec4 FragColor;\n""void main()\n""{\n"" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n""}\n\0";// 顶点着色器unsigned int vertexShader;vertexShader = glCreateShader(GL_VERTEX_SHADER);glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);glCompileShader(vertexShader);// 片段着色器unsigned int fragmentShader;fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);glCompileShader(fragmentShader);// 着色器程序unsigned int shaderProgram;shaderProgram = glCreateProgram();glAttachShader(shaderProgram, vertexShader);glAttachShader(shaderProgram, fragmentShader);glLinkProgram(shaderProgram);glDeleteShader(vertexShader);glDeleteShader(fragmentShader);// 设置离屏渲染帧缓冲unsigned int framebuffer;glGenFramebuffers(1, &framebuffer);glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);// 创建纹理附件unsigned int textureColorbuffer;glGenTextures(1, &textureColorbuffer);glBindTexture(GL_TEXTURE_2D, textureColorbuffer);glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 800, 600, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureColorbuffer, 0);// 检查帧缓冲完整性if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)std::cerr << "Framebuffer is not complete!" << std::endl;// 渲染循环while (!glfwWindowShouldClose(window)) {glClearColor(0.2f, 0.3f, 0.3f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);// 离屏渲染glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);glViewport(0, 0, 800, 600); // 设置视口大小为纹理大小glClear(GL_COLOR_BUFFER_BIT);// 使用着色器程序glUseProgram(shaderProgram);// 绘制三角形glBindVertexArray(VAO);glDrawArrays(GL_TRIANGLES, 0, 3);// 上屏渲染glBindFramebuffer(GL_FRAMEBUFFER, 0);glViewport(0, 0, 800, 600); // 重置视口大小为屏幕大小glClear(GL_COLOR_BUFFER_BIT);// 使用另一个着色器程序或者直接绘制// 这里假设你有一个简单的绘制纹理的着色器程序和四边形glUseProgram(shaderProgram);glBindVertexArray(VAO);glBindTexture(GL_TEXTURE_2D, textureColorbuffer); // 使用离屏渲染的纹理glDrawArrays(GL_TRIANGLES, 0, 6);glfwSwapBuffers(window);glfwPollEvents();}// 释放资源glDeleteVertexArrays(1, &VAO);glDeleteBuffers(1, &VBO);glDeleteFramebuffers(1, &framebuffer);glDeleteTextures(1, &textureColorbuffer);glDeleteProgram(shaderProgram);// 终止 GLFWglfwTerminate();return 0;
}