此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;
}
运行结果: