OpenGL帧缓存(转)

原创 2007年10月08日 11:39:00

作为最后一关,我们将架设自己即时光影的动画,让没有VOODOO的玩家看看OPENGL 这震撼(至少我是这么认为的吧)的效果。

我们前面(好象是第三还是第四次)讲过如何用几何变换实现动画。那时的效果现在看肯定不尽人意,因为频繁的闪烁不是我们需要的。因为那时(到这之前也是)采用的是单缓存模式。对正在显示的部分边计算边修改必然造成速度瓶颈,出现闪烁。一般正规的动画制作在实现上都是通过双缓存实现的(硬件也好,软件也好)大家可以参考《家用电脑与游戏机》的98-2中的一篇文章。当前台显示缓存用于显示时,后台缓存已经进行计算,计算完毕把所有内容通过缓存拷贝一次性完成,防止闪烁的出现。

一 OPENGL帧缓存的实现

1 颜色缓存(Color Buffer)其中内容可以是颜色索引或者RGBA数据,如果用的OPENGL系统支持立体图,则有左右两个缓存。

2 深度缓存(Depth Buffer) 就是Z-BUFFER,用于保存象素Z方向的数值,深度大的被深度小的代替,用以实现消隐

3 模板缓存(Stencil Buffer) 用以保持屏幕上某些位置图形不变,而其他部分重绘。例如大家熟悉的开飞机和赛车的游戏的驾驶舱视角,只有挡风外面的景物变化,舱内仪表等等并不变化。

4 累计缓存(Accumulation Buffer) 只保存RGBA数据,用于合成图象,例如有某缓存中的位图调入这里合成一幅新图。

二 帧缓存的清除
对高分辨率模式清除缓存是工作量巨大的任务,OPENGL一般先寻求硬件同时完成,否则软件依次解决。我们前面每次必用的glClearColor()大家已经不陌生吧。

首先设置清除值
void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf
alpha);
void glClearIndex(GLfloat index);
void glClearDepth(GLclampd depth);
void glClearStencil(GLint s);
void glClerAccum(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha);

然后进行清除
void glClear(GLbitfield mask);
mask: GL_COLOR_BUFFER_BIT|
GL_DEPTH_BUFFER_BIT|
GL_STENCIL_BUFFER_BIT|
GL_ACCUM_BUFFER_BIT

三 双缓存动画
你可以把所有的变换工作看成后台缓存的计算,然后把所有结果拷贝到前台即可。 因此我们只需两个新内容:

首先初始化时调用
auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA);
用AUX_DOUBLE代替AUX_SINGLE设置成双缓存模式

然后在绘制完毕(glFlush();后)调用
auxSwapBuffers();
进行缓存拷贝。Easy like sunday morning!!
当然不同系统下,这个函数也许不同(毕竟是辅助库函数么),例如X-WINDOWS
下可以使用glxSwapBuffers(),意思完全一样。

先说说下面这个例子的功能:
有一个兰色的环作为主体,有一个黄色高亮的球表示光源的位置。小球不断从屏幕左方运动到右方,可以看出环状物上光影的变化。
操作:
鼠标左键/右键:开始/停止光源的运动
键盘 上/下/左/右:控制环状物的 前进/后退/旋转

//////////////////////////////////////////////////////////////////
//sample.cpp
#include "glos.h"
#include
#include
#include "windows.h"

void myinit(void);
void CALLBACK display(void);
void CALLBACK reshape(GLsizei w,GLsizei h);
void CALLBACK stepDisplay(void);
void CALLBACK startIdleFunc(AUX_EVENTREC *event);
void CALLBACK stopIdleFunc(AUX_EVENTREC *event);

//step是表示环状物旋转的参数;z是控制其前后坐标的参数
static GLfloat step=0.0,z=0.0;
//position是控制光源的位置的参数
static GLfloat position[]={-20.0,0.0,-5.0,1.0};

void myinit(void)
{
//初始化注意是双缓存模式
auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA);

auxInitPosition(0,0,500,500);
auxInitWindow("sample1");
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);


glFrontFace(GL_CW);

glEnable(GL_LIGHTING);
glFrontFace(GL_CW);
// glEnable(GL_POLYGON_SMOOTH);
// glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA,GL_ONE);

glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
// glShadeModel(GL_FLAT);
}
void CALLBACK reshape(GLsizei w,GLsizei h)
{

glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/*if(w<=h*3)
glOrtho(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0);
else
glOrtho(-2.0*(GLfloat)h/(GLfloat)w,
2.0*(GLfloat)h/(GLfloat)w,-2.0,2.0,-10.0,10.0);
*/

//启用立体的视景,具有近大远小的效果
glFrustum(-6.0,6.0,-6.0,6.0,3.0,20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

}


void CALLBACK display(void)
{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

//首先在当前位置设置光源
glPushMatrix();
GLfloat light_ambient[]={0.3,0.5,0.3};
GLfloat light_diffuse[]={1.0,1.0,1.0};
GLfloat light_specular[]={0.8,0.8,0.0};
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
glLightfv(GL_LIGHT0,GL_POSITION,position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//在光源旁边绘制黄色高亮的小球,标志光源位置
//小球和光源位置由position[]决定
glTranslatef(position[0],position[1],position[2]-1.0);
GLfloat mat_ambient[]={1.0,0.0,0.0,1.0};
GLfloat mat_diffuse[]={1.0,1.0,0.0,1.0};
GLfloat mat_specular[]={1.0,1.0,0.0,1.0};
GLfloat mat_shininess[]={50.0};
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
auxSolidSphere(0.5);
glPopMatrix();

//在当前位置绘制兰色环状物,其位置由step z共同决定
glPushMatrix();
glTranslatef(0.0,0.0,-8.0+z);
glRotatef(135.0+step,0.0,1.0,0.0);
GLfloat mat2_ambient[]={0.0,0.0,1.0,1.0};
GLfloat mat2_diffuse[]={0.2,0.0,0.99,1.0};
GLfloat mat2_specular[]={1.0,1.0,0.0,1.0};
GLfloat mat2_shininess[]={50.0};
glMaterialfv(GL_FRONT,GL_AMBIENT,mat2_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat2_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat2_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat2_shininess);
auxSolidTorus(2.0,3.5);
glPopMatrix();

glFlush();
//绘制完毕,缓存交换
auxSwapBuffers();

}
void CALLBACK Up(void)
{
//键盘“上”的处理
z=z+0.05;
}
void CALLBACK Down(void)
{
//键盘“下”的处理
z=z-0.05;
}
void CALLBACK Left(void)
{
//键盘“左”的处理
step=step+2.0;
}
void CALLBACK Right(void)
{
//键盘“右”的处理
step=step-2.0;
}

void CALLBACK stepDisplay(void)
{
//系统闲时的调用过程
position[0]=position[0]+0.5;
if(position[0]>20.0) position[0]=-20.0;
display();
}

void CALLBACK startFunc(AUX_EVENTREC *event)
{
//鼠标左键的处理
auxIdleFunc(stepDisplay);
}

void CALLBACK stopIdleFunc(AUX_EVENTREC *event)
{
//鼠标右键的处理
auxIdleFunc(0);
}

void main(void)
{
myinit();

auxReshapeFunc(reshape);
auxIdleFunc(stepDisplay);
auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,startFunc);
auxMouseFunc(AUX_RIGHTBUTTON,AUX_MOUSEDOWN,stopIdleFunc);
auxKeyFunc(AUX_UP,Up);
auxKeyFunc(AUX_DOWN,Down);
auxKeyFunc(AUX_LEFT,Left);
auxKeyFunc(AUX_RIGHT,Right);
auxMainLoop(display);
}
//end of sample
////////////////////////////////////////////////////////////////////
其中用到大量CALLBACK函数,分别处理不同消息比较前面演示的动画效果,闪烁的现象明显改善乐(你可以把这个程序两个关于双缓存的地方改成单缓存:设置AUX_SINGLE和去掉auxSwapBuffers(),看看闪烁的多么厉害),至于本身的绘图可能的拖尾现象,只能怪自己机器不好乐。
写到这里,终于打穿乐OPENGL!!!实现当初提出的“长长见识”的设想。
今后有什么新内容我还会尽量补充,大家也可以自由补充。

OPENGL帧缓存和动画

首先感谢转载原链接:http://blog.163.com/cp7618@yeah/blog/static/7023477720106156557104/ 一般正规的动画制作在实现上都是通过...
  • wyq1153
  • wyq1153
  • 2017年01月10日 23:06
  • 702

OpenGL的帧缓存

转自:http://bbs.hxsd.com/showthread.php?p=9574762 OpenGL的帧缓存  (本文参考的是《OpenGL编程权威指南》,也就是传说中的“红宝书”...
  • zhongjling
  • zhongjling
  • 2013年01月09日 17:14
  • 4626

OpenGL--帧缓冲区

理论基础 1,帧缓冲区(显存):是由像素组成的二维数组,每一个存储单元对应屏幕上的一个像素,整个帧缓冲对应一帧图像即当前屏幕画面。帧缓冲通常包括:颜色缓冲,深度缓冲,模板缓冲和累积缓冲。这些缓冲区可...
  • u010223072
  • u010223072
  • 2015年04月27日 11:05
  • 3912

OpenGL核心技术之帧缓冲

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》...
  • jxw167
  • jxw167
  • 2017年02月12日 15:03
  • 2087

OpenGL帧缓存对象(FBO)

OpenGL帧缓存对象(FBO:Frame Buffer Object) 参考地址:http://blog.csdn.net/dreamcs/article/details/7691690 帧缓存(F...
  • wang15061955806
  • wang15061955806
  • 2016年04月12日 21:09
  • 1807

对Opengl中的帧缓冲的一些理解(延迟渲染,后处理等)

用最通俗的话来说: 咱们能在屏幕上看到东西,这是默认的帧缓冲的信息输出,这个帧缓冲里面包括,颜色缓冲,深度缓冲,模板缓冲等。 而一个默认的帧缓冲是不够用的,不能灵活的处理一些想要的效果。 所以咱们要创...
  • z18636930051
  • z18636930051
  • 2017年11月29日 17:26
  • 48

OpenGL系列教程之八:OpenGL顶点缓冲区对象(VBO)

相关主题:顶点数组,显示列表,像素缓冲区对象 下载:vbo.zip, vboSimple.zip 创建VBO绘制VBO更新VBO例子 GL_ARB_vertex_buff...
  • wozhengtao
  • wozhengtao
  • 2016年09月26日 17:10
  • 286

OpenGL ES 学习教程(十四) 帧缓冲区对象(FBO) 实现渲染到纹理(Render To Texture/RTT)

一般情况下,我们只需要系统提供的帧缓冲区作为绘图表面,但是又有些特殊情况,比如阴影贴图、动态反射、处理后特效等需要渲染到纹理(Render To Texture/RTT)操作的,如果使用系统提供的帧缓...
  • cp790621656
  • cp790621656
  • 2016年11月27日 15:39
  • 1609

OpenGL像素缓冲对象(PBO)

免责申明(必读!):本翻译原稿来自以下链接,仅供学习交流之用,切勿进行商业传播。同时,转载时不要移除本申明。如产生任何纠纷,均与本博客所有人、发表该翻译稿之人无任何关系。谢谢合作! http://w...
  • danjia1234567891011
  • danjia1234567891011
  • 2015年08月03日 23:56
  • 1484

OpenGL中的深度缓存

在说深度缓存前先来了解一下什么是深度? 深度,在日常生活中,这个词可以用来形容比如说一口井有多少深,即是一个距离,在OpenGL中也是一样的,不过它是用z坐标来描述的。一般地,z轴的坐标原点在屏幕上...
  • huai814586181
  • huai814586181
  • 2015年05月25日 20:57
  • 1213
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:OpenGL帧缓存(转)
举报原因:
原因补充:

(最多只允许输入30个字)