OpenGL FBO示例注释

此FBO示例是来自《OpenGL超级宝典》,由于正在学习FBO,我对此进行了一定的注释。在下载的宝典源代码中,镜面反射无法显示,后来发现少了两句代码,下面所列的源程序中都有说明……

#include <stdio.h>
#include <iostream>

#include <GLTools.h>
#include <GLShaderManager.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLMatrixStack.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <GL/glu.h>
#include <GL/glut.h>

using namespace std;


static GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
static GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
static GLfloat vWhite[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
static GLfloat vGrey[] =  { 0.5f, 0.5f, 0.5f, 1.0f };
static GLfloat vLightPos[] = { -2.0f, 3.0f, -2.0f, 1.0f };
static const GLenum windowBuff[] = { GL_BACK_LEFT };
static const GLenum fboBuffs[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
static GLint mirrorTexWidth  = 800;
static GLint mirrorTexHeight = 800;

GLsizei	 screenWidth;			// Desired window or desktop width
GLsizei  screenHeight;			// Desired window or desktop height

GLboolean bFullScreen;			// 请求全屏运行
GLboolean bAnimated;			// 请求不断更新


GLShaderManager		shaderManager;			// 着色器管理器
GLMatrixStack		modelViewMatrix;		// 模型视图矩阵
GLMatrixStack		projectionMatrix;		// 投影矩阵
GLFrustum			viewFrustum;			// 视锥
GLGeometryTransform	transformPipeline;		// 几何变换管线
GLFrame				cameraFrame;			// 摄像机
GLFrame				mirrorFrame;			// 镜面帧

GLTriangleBatch		torusBatch;			//花托
GLTriangleBatch		sphereBatch;		//球体(光源)
GLTriangleBatch		cylinderBatch;		//柱面
GLBatch				floorBatch;			//地板
GLBatch				mirrorBatch;		//镜面
GLBatch				mirrorBorderBatch;	//镜框

GLuint              fboName;			//fbo标识符
GLuint				textures[1];		//纹理
GLuint				mirrorTexture;		//反射纹理
GLuint              depthBufferName;	//深度缓冲区标识符

//void DrawWorld(GLfloat yRot);
//bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode);


//加载bmp文件为纹理
bool LoadBMPTexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)	
{
	GLbyte *pBits;
	GLint iWidth, iHeight;

	pBits = gltReadBMPBits(szFileName, &iWidth, &iHeight);
	if(pBits == NULL)
		return false;

	// Set Wrap modes
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, iWidth, iHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, pBits);

    // Do I need to generate mipmaps?
	if(minFilter == GL_LINEAR_MIPMAP_LINEAR || minFilter == GL_LINEAR_MIPMAP_NEAREST || minFilter == GL_NEAREST_MIPMAP_LINEAR || minFilter == GL_NEAREST_MIPMAP_NEAREST)
		glGenerateMipmap(GL_TEXTURE_2D);    

	return true;
}



void SetupRC()
{
    GLenum err = glewInit();
	if (GLEW_OK != err)
	{
		fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
	}

	// 初始化着色器管理器
	shaderManager.InitializeStockShaders();
	// 开启深度测试
	glEnable(GL_DEPTH_TEST);

	// 黑色背景
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

	// 绘制花托
	gltMakeTorus(torusBatch, 0.4f, 0.15f, 35, 35);
	// 绘制球体
	gltMakeSphere(sphereBatch, 0.1f, 26, 13);
	// 绘制圆柱(cylinderBatch,底部半径,顶部半径,圆柱的高,围绕z轴三角形对的数量,从圆柱体底部堆叠到顶部圆环的数量)
	gltMakeCylinder(cylinderBatch, 0.3f, 0.2f, 1.0, 10, 10);

	GLfloat alpha = 0.25f;
	floorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
		floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);// 顶点颜色
		floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);	// 纹理坐标
		floorBatch.Normal3f(0.0, 1.0f, 0.0f);		// 法线向量
		floorBatch.Vertex3f(-20.0f, -0.41f, 20.0f);	// 顶点坐标

		floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);
		floorBatch.MultiTexCoord2f(0, 10.0f, 0.0f);
		floorBatch.Normal3f(0.0, 1.0f, 0.0f);
		floorBatch.Vertex3f(20.0f, -0.41f, 20.0f);

		floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);
		floorBatch.MultiTexCoord2f(0, 10.0f, 10.0f);
		floorBatch.Normal3f(0.0, 1.0f, 0.0f);
		floorBatch.Vertex3f(20.0f, -0.41f, -20.0f);

		floorBatch.Color4f(0.0f, 1.0f, 0.0f, alpha);
		floorBatch.MultiTexCoord2f(0, 0.0f, 10.0f);
		floorBatch.Normal3f(0.0, 1.0f, 0.0f);
		floorBatch.Vertex3f(-20.0f, -0.41f, -20.0f);
	floorBatch.End();

	//镜面
	mirrorBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
		mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);
		mirrorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
		mirrorBatch.Normal3f( 0.0f, 1.0f, 0.0f);
		mirrorBatch.Vertex3f(-1.0f, 0.0f, 0.0f);

		mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);
		mirrorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
		mirrorBatch.Normal3f(0.0f, 1.0f, 0.0f);
		mirrorBatch.Vertex3f(1.0f, 0.0f, 0.0f);

		mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);
		mirrorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
		mirrorBatch.Normal3f(0.0f, 1.0f, 0.0f);
		mirrorBatch.Vertex3f(1.0f, 2.0f, 0.0f);

		mirrorBatch.Color4f(1.0f, 0.0f, 0.0f, 1.0f);
		mirrorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
		mirrorBatch.Normal3f( 0.0f, 1.0f, 0.0f);
		mirrorBatch.Vertex3f(-1.0f, 2.0f, 0.0f);
	mirrorBatch.End();

	// 13个顶点组成的三角形带,镜框
	mirrorBorderBatch.Begin(GL_TRIANGLE_STRIP, 13);
		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(-1.0f, 0.1f, 0.01f);

		mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(-1.0f, 0.0f, 0.01f);

		mirrorBorderBatch.Normal3f(0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(1.0f, 0.1f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(1.0f, 0.0f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(0.9f, 0.0f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(1.0f, 2.0f, 0.01f);
			
		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(0.9f, 2.0f, 0.01f);
			
		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(1.0f, 1.9f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(-1.0f, 2.f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(-1.0f, 1.9f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(-0.9f, 2.f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(-1.0f, 0.0f, 0.01f);

		mirrorBorderBatch.Normal3f( 0.0f, 0.0f, 1.0f);
		mirrorBorderBatch.Vertex3f(-0.9f, 0.0f, 0.01f);
	mirrorBorderBatch.End();

	glGenTextures(1, textures);
	glBindTexture(GL_TEXTURE_2D, textures[0]);
	LoadBMPTexture("marble.bmp", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_REPEAT);

	// 创建并绑定一个FBO
	glGenFramebuffers(1,&fboName);
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName);

	// 创建深度渲染缓冲区
	glGenRenderbuffers(1, &depthBufferName);
	glBindRenderbuffer(GL_RENDERBUFFER, depthBufferName);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, mirrorTexWidth, mirrorTexHeight);
	 
	// 创建反射纹理
	glGenTextures(1, &mirrorTexture);
	glBindTexture(GL_TEXTURE_2D, mirrorTexture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mirrorTexWidth, mirrorTexHeight, 0, GL_RGBA, GL_FLOAT, NULL);
	/****下载的书的源代码中少了下面这两句,所以镜面反射显示不出来****/
	// 当显示的大小比原纹理大或小时所采取的滤波方式
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	
	/ 将纹理绑定到第一个颜色绑定点和深度渲染缓冲区(RBO)///
	// 第1个参数:GL_DRAW_FRAMEBUFFER或GL_READ_FRAMEBUFFER
	// 第2个参数:附加点GL_COLOR_ATTACHMENTi、GL_DEPTH_ATTACHMENT、GL_STENCIL_ATTACHMENT、GL_DEPTH_STENCIL_ATTACHMENT
	// 第3个参数:texturetarget
	// 第4个参数:要绑定的纹理对象
	// 第5个参数:作为渲染目标附加的相关纹理图像的mipmap层
	glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTexture, 0);
	// 把renderbuffer和当前绑定的帧缓冲区对象的附加联系起来
	// 第1个参数:GL_DRAW_FRAMEBUFFER或GL_READ_FRAMEBUFFER
	// 第2个参数:附加点GL_COLOR_ATTACHMENTi、GL_DEPTH_ATTACHMENT、GL_STENCIL_ATTACHMENT、GL_DEPTH_STENCIL_ATTACHMENT
	// 第3个参数:必须是GL_RENDERBUFFER
	// 第4个参数:可以使0(这会删除附加点的任何渲染缓冲区附加),或者是glGenRenderbuffers()所返回的渲染缓冲区的名字
	glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferName);

	// 确认运行无误
	gltCheckErrors();
	
	// 解除绑定,再次绑定到默认FBO
	// 一旦默认FBO被绑定,那么读取和写入就都再次绑定到了窗口的帧缓冲区
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}


void ShutdownRC(void)
{
	// 确认绑定到默认FBO
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
	glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);

	// 清除纹理
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, 0);
	
	glDeleteTextures(1, &mirrorTexture);
	glDeleteTextures(1, textures);

	// 清除RBO
	glDeleteRenderbuffers(1, &depthBufferName);

	// 清除FBO
	glDeleteFramebuffers(1, &fboName);

}


void ChangeSize(int nWidth, int nHeight)
{
	glViewport(0, 0, nWidth, nHeight);
	transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
 
	viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
	projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
	modelViewMatrix.LoadIdentity();

	// 更新屏幕尺寸
	screenWidth = nWidth;
	screenHeight = nHeight;
}


void SpecialKeys(int key, int x, int y)
{ 
	static CStopWatch cameraTimer;
	float fTime = cameraTimer.GetElapsedSeconds();
	cameraTimer.Reset(); 

	float linear = fTime * 0.60f;
	float angular = fTime * float(m3dDegToRad(60.0f));

	if(key == GLUT_KEY_UP)
		cameraFrame.MoveForward(linear);

	if(key == GLUT_KEY_DOWN)
		cameraFrame.MoveForward(-linear);

	if(key == GLUT_KEY_LEFT)
		cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);

	if(key == GLUT_KEY_RIGHT)
		cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
}



void DrawWorld(GLfloat yRot)
{
	M3DMatrix44f mCamera;
	modelViewMatrix.GetMatrix(mCamera);
	
	// 光源相对于照相机的位置
	M3DVector4f vLightTransformed;
	m3dTransformVector4(vLightTransformed, vLightPos, mCamera);

	// 绘制光源(没有阴影的白色小球)
	modelViewMatrix.PushMatrix();
		modelViewMatrix.Translatev(vLightPos);
		shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vWhite);
		sphereBatch.Draw();
	modelViewMatrix.PopMatrix();

	// 绘制旋转花托
	modelViewMatrix.PushMatrix();
		modelViewMatrix.Translate(0.0f, 0.2f, -2.5f);
		modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
	
		shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, 
				modelViewMatrix.GetMatrix(), 
				transformPipeline.GetProjectionMatrix(), 
				vLightTransformed, vGreen, 0);
		torusBatch.Draw();
	modelViewMatrix.PopMatrix();
}



void RenderScene(void)
{
	static CStopWatch animationTimer;//动画计时器
	float yRot = animationTimer.GetElapsedSeconds() * 60.0f;

	M3DVector3f vCameraPos;
	M3DVector3f vCameraForward;
	M3DVector3f vMirrorPos;
	M3DVector3f vMirrorForward;
	cameraFrame.GetOrigin(vCameraPos);
	cameraFrame.GetForwardVector(vCameraForward);

	// 设置镜面帧(照相机)的位置
	vMirrorPos[0] = 0.0;
	vMirrorPos[1] = 0.1f;
	vMirrorPos[2] = -6.0f; // 观察位置实际上是在镜面后的
	mirrorFrame.SetOrigin(vMirrorPos);

	// 计算镜面帧(照相机)的方向
	// 因为知道镜面相对于原点的位置
	// 通过向观察着的向量一 一原点添加镜面偏置来寻找方向向量
	vMirrorForward[0] = vCameraPos[0];
	vMirrorForward[1] = vCameraPos[1];
	vMirrorForward[2] = (vCameraPos[2] + 5);
	m3dNormalizeVector3(vMirrorForward);
	mirrorFrame.SetForwardVector(vMirrorForward);
	
	// 首先从镜面的视角进行渲染(此时用到了FBO)
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboName);
	glDrawBuffers(1, fboBuffs);
	glViewport(0, 0, mirrorTexWidth, mirrorTexHeight);

	// 从镜像照相机的视角绘制场景
	modelViewMatrix.PushMatrix();	
		M3DMatrix44f mMirrorView;
		mirrorFrame.GetCameraMatrix(mMirrorView);
		modelViewMatrix.MultMatrix(mMirrorView);

		// 为了达到反射效果而对照相机进行水平反转
		modelViewMatrix.Scale(-1.0f, 1.0f, 1.0f);
		
		glBindTexture(GL_TEXTURE_2D, textures[0]); // Marble
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite, 0);
		floorBatch.Draw();
		DrawWorld(yRot);

		// 现在绘制一个圆筒来代表观察者
		M3DVector4f vLightTransformed;
		modelViewMatrix.GetMatrix(mMirrorView);
		m3dTransformVector4(vLightTransformed, vLightPos, mMirrorView);	
		modelViewMatrix.Translate(vCameraPos[0], vCameraPos[1]-0.8f, vCameraPos[2]-1.0f);
		modelViewMatrix.Rotate(-90.0f, 1.0f, 0.0f, 0.0f);

		shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, 
					modelViewMatrix.GetMatrix(), 
					transformPipeline.GetProjectionMatrix(), 
					vLightTransformed, vBlue, 0);		
		cylinderBatch.Draw();

	modelViewMatrix.PopMatrix();

	// 重置FBO,再次从真实的照相机视角来绘制场景
	glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
	glDrawBuffers(1, windowBuff);
	glViewport(0, 0, screenWidth, screenHeight);
	modelViewMatrix.PushMatrix();	
		M3DMatrix44f mCamera;
		cameraFrame.GetCameraMatrix(mCamera);
		modelViewMatrix.MultMatrix(mCamera);
		
		glBindTexture(GL_TEXTURE_2D, textures[0]); // Marble
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		shaderManager.UseStockShader(GLT_SHADER_TEXTURE_MODULATE, transformPipeline.GetModelViewProjectionMatrix(), vWhite, 0);

		floorBatch.Draw();
		DrawWorld(yRot);

		// 现在绘制镜面表面
		modelViewMatrix.PushMatrix();
			modelViewMatrix.Translate(0.0f, -0.4f, -5.0f);
			if(vCameraPos[2] > -5.0)
			{
				glBindTexture(GL_TEXTURE_2D, mirrorTexture); // Reflection
				shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
			}
			else
			{
				// 如果观察者在镜面后面,那么镜面将会绘制成黑色
				shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
			}
			mirrorBatch.Draw();
			shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGrey);
			mirrorBorderBatch.Draw();
		modelViewMatrix.PopMatrix();
	modelViewMatrix.PopMatrix();
	
    // 清空缓冲区
    glutSwapBuffers();
        
    glutPostRedisplay();
}


int main(int argc, char* argv[])
{
    screenWidth = 800;
    screenHeight = 600;
    bFullScreen = false; 
    bAnimated = true;
    fboName = 0;
    depthBufferName = 0;

	gltSetWorkingDirectory(argv[0]);
		
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(screenWidth,screenHeight);
  
    glutCreateWindow("FBO Textures");
 
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);

    SetupRC();
    glutMainLoop();    
    ShutdownRC();
    return 0;
}

运行结果:




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值