FBO上画三角形

FBO=Frame Buffer Object,其作用主要是对载入的纹理进行再次处理(个人理解)。在FBO上画的几何图形或贴的纹理,可以进行二次处理,然后显示在屏幕上。FBO的创建与VBO类似,都是经过:设定编号->绑定编号->生成对象,这三步。需要特别主要的是,对于一个FBO,要开辟一个一定大小的内存空间,用于存储画在FBO上的形状(或纹理)。

下文以在FBO上画一个三角形为例,简述下FBO的创建和应用。

1.首先,创建一个一定大小的空纹理(用于存储对应FBO上的图形)。其创建过程与普通纹理的创建过程类似(此处不再详述)

glGenTextures(1, &renderedTexture);
	glBindTexture(GL_TEXTURE_2D, renderedTexture);
	glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, texWidth, texHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

2.创建一个FBO,包括利用glGenFramebuffers()函数生成FBO编号,glBindFramebuffer()函数将编号绑定为帧缓冲区,glFramebufferTexture2D()函数将之前设定的空纹理renderedTexture与当前的FBO编号相绑定,glCheckFramebufferStatus()函数检查生成FBO的完整性。
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
		

		glClearColor(0, 0, 0, 1);
		glClear(GL_COLOR_BUFFER_BIT);

		glViewport(0,0,texWidth,texHeight); 

 		glUseProgram(ProgramIDT);

 		glEnableVertexAttribArray(VertexPositionIDT);

 		glBindBuffer(GL_ARRAY_BUFFER,VertexBufferT);
 		glVertexAttribPointer(VertexPositionIDT,3,GL_FLOAT,GL_FALSE,20,(void *)0);
 		glDrawArrays(GL_TRIANGLE_STRIP,0,3);
 
 		glDisableVertexAttribArray(VertexPositionIDT);


3.在主循环中,使用glBindFramebuffer()函数对FBO进行绑定,该函数的第二个参数尤为重要,表示此刻进行操作的FBO对象。当该参数为0时表示系统默认的FBO,即屏幕;当该参数为其它FBO编号时,表示对应FBO。

<pre name="code" class="cpp"><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="cpp">glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
		

		glClearColor(0, 0, 0, 1);
		glClear(GL_COLOR_BUFFER_BIT);

		glViewport(0,0,texWidth,texHeight); 

 		glUseProgram(ProgramIDT);

 		glEnableVertexAttribArray(VertexPositionIDT);

 		glBindBuffer(GL_ARRAY_BUFFER,VertexBufferT);
 		glVertexAttribPointer(VertexPositionIDT,3,GL_FLOAT,GL_FALSE,20,(void *)0);
 		glDrawArrays(GL_TRIANGLE_STRIP,0,3);
 
 		glDisableVertexAttribArray(VertexPositionIDT);

此时对于FBO的渲染操作与对之前的学习没有太大的区别,只是由于是在内存中进行绘制,因此无法“看见”

 
 

4.为了能看到FBO上的渲染效果,需要将其渲染到屏幕上,此时仍使用glBindFramebuffer()函数,但该函数的第二个参数一定为0.

glBindFramebuffer(GL_FRAMEBUFFER, 0);
		
		glClearColor( 1, 1, 1, 0 );
		glClear( GL_COLOR_BUFFER_BIT);

		glViewport(0,0,windowWidth,windowHeight); 
		
		glUseProgram(ProgramIDQ);
 		glActiveTexture(GL_TEXTURE0);
 		glBindTexture(GL_TEXTURE_2D, renderedTexture);
		glUniform1i(TextureIndexQ,0);

		glEnableVertexAttribArray(VertexPositionIDQ);
		glBindBuffer(GL_ARRAY_BUFFER,VertexBufferQ);
		glVertexAttribPointer(VertexPositionIDQ,3,GL_FLOAT,GL_FALSE,20,(void *)0);

		glEnableVertexAttribArray(UVIDQ);
		/*glBindBuffer(GL_ARRAY_BUFFER,VertexBufferQ);*/
		glVertexAttribPointer(UVIDQ,2,GL_FLOAT,GL_FALSE,20,(void *)12);

		glDrawArrays(GL_TRIANGLE_STRIP,0,4);

		glDisableVertexAttribArray(VertexPositionIDQ);
		glDisableVertexAttribArray(UVIDQ);

完整代码如下:

// Include standard headers
#include <stdio.h>

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GLFW/glfw3.h>
GLFWwindow* window;

#include <common/shader.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>

typedef struct 
{
	GLfloat x;
	GLfloat y;
	GLfloat z;
	GLfloat u;
	GLfloat v;
}Vertex;

int main( void )
{
	if( !glfwInit() )
	{
		fprintf( stderr, "Failed to initialize GLFW.\n" );
		getchar();
		return -1;
	}

	glfwWindowHint(GLFW_SAMPLES, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	window = glfwCreateWindow( 1024, 768, "Render To Texture", NULL, NULL);
	if( window == NULL )
	{
		fprintf( stderr, "Failed to open GLFW window.\n" );
		getchar();
		glfwTerminate();
		return -1;
	}
	glfwMakeContextCurrent(window);

	int windowWidth,windowHeight;
	glfwGetWindowSize(window,&windowWidth,&windowHeight);
	glfwGetFramebufferSize(window, &windowWidth, &windowHeight);

	glewExperimental = true; 
	if (glewInit() != GLEW_OK)
	{
		fprintf(stderr, "Failed to initialize GLEW\n");
		getchar();
		glfwTerminate();
		return -1;
	}

	glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);

	glEnable(GL_TEXTURE_2D);

	//vertex data
	Vertex g_VertexBufferDataQ[]={
		{-1.0,1.0,0.0, 0.0,1.0},
		{1.0,1.0,0.0,  1.0,1.0},
		{-1.0,-1.0,0.0,   0.0,0.0},
		{1.0,-1.0,0.0,   1.0,0.0},
	};

	Vertex g_VertexBufferDataT[]={
		{-1.0,-1.0,0.0, 0.0,0.0},
		{1.0,-1.0,0.0,  0.0,0.0},
		{0.0,1.0,0.0,   0.0,0.0},
		
	};

	GLuint VertexArrayID;
	//===Generate the vertex array
	glGenVertexArrays(1,&VertexArrayID);
	glBindVertexArray(VertexArrayID);

	GLuint VertexBufferQ;
	glGenBuffers(1,&VertexBufferQ);
	glBindBuffer(GL_ARRAY_BUFFER,VertexBufferQ);
	glBufferData(GL_ARRAY_BUFFER,sizeof(g_VertexBufferDataQ),g_VertexBufferDataQ,GL_STATIC_DRAW);

	GLuint VertexBufferT;
	glGenBuffers(1,&VertexBufferT);
	glBindBuffer(GL_ARRAY_BUFFER,VertexBufferT);
	glBufferData(GL_ARRAY_BUFFER,sizeof(g_VertexBufferDataT),g_VertexBufferDataT,GL_STATIC_DRAW);

	GLuint ProgramIDT = LoadShaders("VertexShaderT.vertexshader","FragmentShaderT.fragmentshader");
	GLint VertexPositionIDT=glGetAttribLocation(ProgramIDT,"vertexPosition_modelspace");

	GLuint ProgramIDQ = LoadShaders("VertexShaderQ.vertexshader","FragmentShaderQ.fragmentshader");
	GLint VertexPositionIDQ=glGetAttribLocation(ProgramIDQ,"vertexPosition_modelspace");

	GLint UVIDQ=glGetAttribLocation(ProgramIDQ,"vertexUV");

	GLint TextureIndexQ       =glGetUniformLocation(ProgramIDQ, "myTextureSampler");

	Create a texture
	GLuint renderedTexture;
	//GLint texWidth=windowWidth,texHeight=windowHeight;
	GLint texWidth=832,texHeight=416;
	glGenTextures(1, &renderedTexture);
	glBindTexture(GL_TEXTURE_2D, renderedTexture);
	glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, texWidth, texHeight, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	//Create a FBO
	GLuint FramebufferName = 0;
	glGenFramebuffers(1, &FramebufferName);
	glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
	glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, renderedTexture,0);
	if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		return false;

	do{
		
		glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
		

		glClearColor(0, 0, 0, 1);
		glClear(GL_COLOR_BUFFER_BIT);

		glViewport(0,0,texWidth,texHeight); 

 		glUseProgram(ProgramIDT);

 		glEnableVertexAttribArray(VertexPositionIDT);

 		glBindBuffer(GL_ARRAY_BUFFER,VertexBufferT);
 		glVertexAttribPointer(VertexPositionIDT,3,GL_FLOAT,GL_FALSE,20,(void *)0);
 		glDrawArrays(GL_TRIANGLE_STRIP,0,3);
 
 		glDisableVertexAttribArray(VertexPositionIDT);

		//=====渲染到屏幕上
		glBindFramebuffer(GL_FRAMEBUFFER, 0);
		
		glClearColor( 1, 1, 1, 0 );
		glClear( GL_COLOR_BUFFER_BIT);

		glViewport(0,0,windowWidth,windowHeight); 
		
		glUseProgram(ProgramIDQ);
 		glActiveTexture(GL_TEXTURE0);
 		glBindTexture(GL_TEXTURE_2D, renderedTexture);
		glUniform1i(TextureIndexQ,0);

		glEnableVertexAttribArray(VertexPositionIDQ);
		glBindBuffer(GL_ARRAY_BUFFER,VertexBufferQ);
		glVertexAttribPointer(VertexPositionIDQ,3,GL_FLOAT,GL_FALSE,20,(void *)0);

		glEnableVertexAttribArray(UVIDQ);
		/*glBindBuffer(GL_ARRAY_BUFFER,VertexBufferQ);*/
		glVertexAttribPointer(UVIDQ,2,GL_FLOAT,GL_FALSE,20,(void *)12);

		glDrawArrays(GL_TRIANGLE_STRIP,0,4);

		glDisableVertexAttribArray(VertexPositionIDQ);
		glDisableVertexAttribArray(UVIDQ);

		// Swap buffers
		glfwSwapBuffers(window);
		glfwPollEvents();
	}
	while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
		glfwWindowShouldClose(window) == 0 );

	/*glDeleteFramebuffers(1, &FramebufferName);
	glDeleteTextures(1, &renderedTexture);*/
	
	glfwTerminate();

	return 0;
}
实验结果:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值