OPENGL帧缓存和动画

首先感谢转载原链接:http://blog.163.com/cp7618@yeah/blog/static/7023477720106156557104/


一般正规的动画制作在实现上都是通过双缓存实现的(硬件也好,软件也好)大家可以参考《家用电脑与游戏机》的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(),看看闪烁的多么厉害),至于本身的绘图可能的拖尾现象,只能怪自己机器不好乐。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值