基于FBO和GPU的动态环境映射算法及实现

来源:互联网 发布:东北最火十大网络歌曲 编辑:程序博客网 时间:2024/06/06 04:02

关键字 OPENGL,FBO,动态,立方体环境映射,CubeMap,GPU

1. FBO(framebuffer object)
FBO是GL_EXT_framebuffer_object扩展多种对象中最主要的对象,它封装了所有的帧缓存相关的状态。每个FBO都可做为逻辑缓存(logical buffers)的载体。逻辑缓冲可以是颜色缓存、深度缓存或模板缓存。逻辑缓存能够独立创建并绑定到FBOs(framebuffer objects)上。一个FBO可以与一个以上的颜色缓存,一个深度缓存和一个模板缓存绑定。一个逻辑缓存也可以同时与多个FBOS绑定。每个FBO都有一套绑定点用来绑定多个逻辑缓存。当使用FBO时候,就可以使用离屏渲染,并将传统的帧缓冲区自动关闭,将图像直接渲染到逻辑缓存,这样避免了纹理复制过程,降低了计算机开销。
2.实现过程
2.1预处理
(1)创建CubeMap纹理存储空间
glGenTextures(1, &tex2);
glBindTexture(GL_TEXTURE_CUBE_MAP, tex2);
for (int face = 0; face < 6; face++)
{ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA8,
width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);}
(2)创建FBO
glGenFramebuffersEXT(1,&fb);
(3)创建深度缓存
glGenRenderbuffersEXT(1, &depth);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16,SIZE,SIZE);
2.2 实时渲染CubeMap
在每帧图象执行前,都需执行以下代码,从而实时更新CubeMap。
(1)设置视口和投影矩阵;
glViewport(0,0,SIZE,SIZE);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluPerspective(90,1,0.1,far);
(2)绑定当前FBO,并连接深度缓存
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);
 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth);
(3)对CubeMap的六个面进行渲染
 for(i=0;i<6;i++)
 {
//将FBO连接点指向需要渲染的纹理;
  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
                              GL_COLOR_ATTACHMENT0_EXT,
                            GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,tex2,0);
  glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
  glMatrixMode(GL_MODELVIEW);
//设置变换矩阵;
  glLoadMatrixf( );
//绘制周围场景
  render();
 }
//恢复到正常帧缓存、视口及投影矩阵;
 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
 glViewport(0,0,512,512);
glMatrixMode(GL_PROJECTION);
gPopMatrix();
}
2.3渲染模型
渲染模型采用GPU可编程渲染管道,包括两个管道,顶点处理器和片段处理器。顶点处理器在本系统中实现顶点坐标变换,计算摄象机向量和顶点光源向量,以及反射向量和折射向量;片段处理器进行纹理采样和计算光照强度。代码分别如下:
(1)顶点程序
uniform mat4 ModelWorld4x4;
uniform vec3 CameraPos;
uniform vec3 lightPos;
varying vec3 L;
varying vec4 diffuse,ambient;
void main()

 gl_Position = ftransform();  
//自定义函数,获得模型世界矩阵的左上3X3子矩阵;
 mat3 ModelWorld3x3 = GetLinearPart( ModelWorld4x4 );
//模型的世界坐标;
 vec4 WorldPos = ModelWorld4x4 *  gl_Vertex; 
//模型法向的在世界坐标中的方向向量;
 N = ModelWorld3x3 * gl_Normal ;
//在世界坐标中的摄象机方向向量;
 E =  WorldPos.xyz - CameraPos.xyz ; 
//计算光照;
 L=lightPos-WorldPos.xyz;
//计算反射和折射向量;
 gl_TexCoord[0].xyz=reflect(E,N);
 gl_TexCoord[1].xyz=refract(E,N,0.78);
diffuse=gl_FrontMaterial.diffuse*gl_LightSource[0].diffuse;
 ambient=gl_FrontMaterial.ambient*gl_LightSource[0].ambient;
 ambient+=gl_LightModel.ambient * gl_FrontMaterial.ambient;
}
(2)片段程序
uniform samplerCube cubeMap;
varying vec3 L;
varying vec4 diffuse,ambient;
uniform vec3 factor;

void main (void)
{
//光源方向向量单位化;
 vec3 l=normalize(L);
//纹理采样;
 vec3 c1=textureCube(cubeMap, gl_TexCoord[0].stp).rgb;
 vec3 c2=textureCube(cubeMap, gl_TexCoord[1].stp).rgb;
//计算光照;
 float NdotL=max(dot(n,l),0.0);
 vec4 color=diffuse*max(NdotL,0.0)+ambient;
 vec3 c=c2*factor[0]+c1*factor[1]+color.xyz*factor[2];
 gl_FragColor=vec4(c,1.0);
 }
参考文献
1. http://ati.amd.com/developer 
2. http://developer.nvidia.com