我在GL_TEXTURE_2D
中有一张图片。从这里开始,我需要将此纹理移动到framebuffer对象上。有人可以请一个使用填充了数据并将其放在FBO上的2d纹理的示例吗?我不是要渲染纹理,而是从纹理渲染。
答案 0 :(得分:1)
这是一个简单的FBO演示。
您可以在github上找到整个代码here(代码基于来自OpenGL SuperBible的this示例程序)。
该程序执行以下操作
将绿色背景上的红色方块绘制成FBO。 FBO的后备存储是2D纹理。
在蓝色屏幕上绘制正方形,但将纹理从步骤1映射到正方形。这会将整个场景从上一步映射到正方形。
所以使用帧缓冲时的理论,
然后有2个程序(或2个程序)
在程序1中,渲染到帧缓冲区(渲染到纹理中)
在程序2中,现在渲染到窗口(屏幕)并使用第一个程序中的纹理作为输入。
因此第一个程序的输出是第二个程序的输入。
这意味着两个阶段的顶点着色器将是相同的。由于没有遮罩(旋转)和没有光照效果,所有顶点着色器都将输入传递给输出(即坐标)。
但每个阶段的片段着色器都会略有不同。
第一个片段着色器为每个像素输出一个恒定的颜色。在源代码中,第一个片段着色器的输出配置为FBO,FBO使用纹理来存储颜色数据。
第一个片段着色器中生成的纹理在第二个片段着色器中用作输入。在第二个片段着色器中,颜色由纹理(第一个片段着色器的输出)确定。
所以这是顶点着色器。请注意,顶点着色器的输入是坐标(vp)和纹理坐标。 2程序的片段着色器需要texcoords来知道纹理的映射位置。在顶点着色器中,texcoord简单地从输入传递到输出。
#version 130
in vec3 vp;
in vec2 texcoord;
out vec2 outtexcoord;
void main () {
gl_Position = vec4 (vp, 1.0);
outtexcoord = texcoord;
}
这是第一个程序的片段着色器。每个像素都画成红色。
#version 130
in vec2 outtexcoord;
out vec4 frag_colour;
void main () {
frag_colour = vec4 (1.0, 0.0, 0.0, 0.0); //everything red
}
第二个程序片段着色器。注意sampler2D是输入纹理(由第一个程序生成)。 outtexcoord也是顶点着色器的纹理坐标。输出颜色(frag_color)由纹理决定。
#version 130
uniform sampler2D tex;
in vec2 outtexcoord;
out vec4 frag_color;
void main () {
frag_color = texture(tex, outtexcoord);
}
这是C程序(我用g ++编译,请参阅github链接中的makefile)。
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "shader_utils.h" //see github link for details
void Initialize();
void InitGL();
void InitProgramFBO();
void InitProgramScreen();
void InitBuffer();
void InitFBO();
void Loop();
void RenderToFBO();
void RenderToScreen();
void Shutdown();
void OnWindowResize(GLFWwindow* window, int width, int height);
GLFWwindow* window;
int screenWidth = 640;
int screenHeight = 480;
GLuint render2FBOProgram;
GLuint render2ScreenProgram;
GLuint vao;
GLuint vbo;
GLuint fbo;
GLuint color_texture;
int main() {
Initialize();
Loop();
Shutdown();
return 0;
}
void Initialize() {
InitGL();
InitProgramScreen();
InitProgramFBO();
InitBuffer();
InitFBO();
}
void InitGL() {
glfwInit();
window = glfwCreateWindow(screenWidth, screenHeight, "FBO Demo", NULL, NULL);
glfwMakeContextCurrent(window);
glewInit();
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
}
void InitProgramFBO() {
GLuint vs;
GLuint fs;
render2FBOProgram = create_program("vs.glsl", "fbo.fs.glsl", vs, fs);
glDeleteShader(vs);
glDeleteShader(fs);
}
void InitProgramScreen() {
GLuint vs;
GLuint fs;
render2ScreenProgram = create_program("vs.glsl", "screen.fs.glsl", vs, fs);
glDeleteShader(vs);
glDeleteShader(fs);
}
void InitBuffer() {
//define the square made up of 2 triangles
static const GLfloat points[] = {
//x y z texcoord u and v
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f
};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//create buffer for points
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
//tell opengl how to find the coordinate data
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLubyte*)NULL);
glEnableVertexAttribArray(0);
//tell opengl how to find the texcoord data
glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid *)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);
}
void InitFBO() {
//create a framebuffer
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//create a texture as the backing store for the framebuffer
glGenTextures(1, &color_texture);
glBindTexture(GL_TEXTURE_2D, color_texture);
glTexStorage2D(GL_TEXTURE_2D, 9, GL_RGBA8, 512, 512); //1 = mipmap levels
//mip map filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//attach the texture as the color attachment of the framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);
//tell opengl to draw into the color attachment
static const GLenum draw_buffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_buffers);
}
void Loop() {
//glBindVertexArray(vao);
//glBindBuffer(GL_ARRAY_BUFFER, vbo);
while (!glfwWindowShouldClose(window)) {
RenderToFBO();
RenderToScreen();
glfwSwapBuffers(window);
glfwPollEvents();
if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
glfwSetWindowShouldClose(window, 1);
}
}
}
void RenderToFBO() {
static const GLfloat green[] = { 0.0f, 1.0f, 0.0f, 1.0f }; //texture background is green
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, 512, 512); //set view port to texture size
glClearBufferfv(GL_COLOR, 0, green);
glUseProgram(render2FBOProgram);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void RenderToScreen() {
static const GLfloat blue[] = { 0.0f, 0.0f, 1.0f, 1.0f }; //screen background is blue
glViewport(0, 0, screenWidth, screenHeight);
glClearBufferfv(GL_COLOR, 0, blue);
glBindTexture(GL_TEXTURE_2D, color_texture);
glUseProgram(render2ScreenProgram);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Shutdown() {
glUseProgram(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteProgram(render2FBOProgram);
glDeleteProgram(render2ScreenProgram);
glfwTerminate();
}
// a call-back function
void OnWindowResize(GLFWwindow* window, int width, int height) {
screenWidth = width;
screenHeight = height;
glViewport(0, 0, screenWidth, screenHeight);
}