`
huozheleisi
  • 浏览: 1238555 次
文章分类
社区版块
存档分类
最新评论

OPENGL帧缓存和动画

 
阅读更多

OPENGL帧缓存和动画
	作为最后一关,我们将架设自己即时光影的动画,让没有VOODOO的玩家看看OPENGL这震撼(至少我是这么认为的吧)的效果,完成所有这将近20次灌水最终目标。 
 
	我们前面(好象是第三还是第四次)讲过如何用几何变换实现动画。那时的效果现在看肯定不尽人意,因为频繁的闪烁不是我们需要的。因为那时(到这之前也 
是)采用的是单缓存模式。对正在显示的部分边计算边修改必然造成速度瓶颈,出现闪烁。一般正规的动画制作在实现上都是通过双缓存实现的(硬件也好,软 
件也好)大家可以参考《家用电脑与游戏机》的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 <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>

#pragma comment(lib, "OpenGl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")

#pragma warning(disable : 4244)		// MIPS
#pragma warning(disable : 4136)		// X86
#pragma warning(disable : 4051)		// ALPHA
 
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基础图形编程

    总目录  第一章 OpenGL与三维图形世界  1.1 OpenGL使人们进入三维图形世界  1.2 OpenGL提供直观的三维图形开发... 第十七章 OpenGL帧缓存和动画  17.1 帧缓存  17.1.1 帧缓存组成  17.1.2 缓存清除  17.2 动画

    OpenGL 基础教程

    总目录  第一章 OpenGL与三维图形世界  1.1 OpenGL使人们进入三维图形世界  1.2 OpenGL提供直观的三维图形开发... 第十七章 OpenGL帧缓存和动画  17.1 帧缓存  17.1.1 帧缓存组成  17.1.2 缓存清除  17.2 动画

    OpenGL图形开发指南(0fen)

    中国游戏开发者第一章 OpenGL与三维图形世界.1 OpenGL使...16.2.2 执行显示列表 16.3 管理显示列表 16.4 多级显示列表 第十七章 OpenGL帧缓存和动画 17.1 帧缓存 17.1.1 帧缓存组成 17.1.2 缓存清除 17.2 动画

    OpenGL编程实例.rar

    观察物体,操作像素、位图、图像,融合和反走样物体,雾化场景,利用帧缓存进行颜色屏蔽、深度控制、遮掩、全局场景反走样、景深模拟和场景对焦效果处理,利用对话框、菜单、鼠标选择物体、信息反馈实现OpenGL基本的...

    OpenGL三维图形程序设计

    体建模、特殊光和特殊效果处理以及OpenGL显示列表、帧缓存与动画的程序设计技巧。 书中列举了大量的编程实例,并且全部存于本书附盘中。所有例程都经过调试通过,是 OpenGL开发者必备之参考。 本书无论是对初次...

    OpenGL 系统开发的源代码

    第7章 帧缓存技术与动画 7.1 OpenGL中的各种缓存 7.1.1 颜色缓存 7.1.2 深度缓存 7.1.3 模板缓存 7.1.4 累积缓存 7.2 缓存操作技术 7.2.1 清除缓存 7.2.2 选择绘图颜色缓存 7.2.3 屏蔽缓存 7.3 ...

    Nehe的OpenGL教程电子书

    利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错。你可以试试。 36.放射模糊和渲染到纹理 如何实现放射状的滤镜效果呢,看上去很难,其实很简单。把渲染得图像作为纹理提取出来,...

    OPenGL编程书籍

    利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错。你可以试试。 36.放射模糊和渲染到纹理 如何实现放射状的滤镜效果呢,看上去很难,其实很简单。把渲染得图像作为纹理提取出来,在...

    OpenSceneGraph三维渲染引擎设计与实践

    9.1.5 范例:关键帧路径动画 239 9.2 刚体动画 242 9.2.1 简单路径动画 242 9.2.2 范例:使用路径动画回调 244 9.2.3 动画的多频道融合 245 9.2.4 范例:基本动画管理器 246 9.3 角色与变形动画 249 9.3.1 ...

    OPhone应用开发权威指南(黄晓庆)

    5.6 帧缓存操作 216 5.6.1 清空缓存 216 5.6.2 读取颜色缓存 216 5.6.3 强制完成绘图指令 217 5.7 其他 217 5.7.1 行为控制函数 217 5.7.2 状态查询 218 5.8 EGL简介 218 5.9 小结 222 第6章 数据持久化存储 223 6.1...

    红蜘蛛网络教室.rar

    采用全新视频驱动核心、MMX/SSE/SSE2指令和多级缓存技术,极大地提高屏幕广播速度和性能, 对3D、游戏、电影、多媒体课件、动画、DVD视频、FLASH、POWERPOINT等都能非常流畅地没有任何延迟地进行广播,甚至达到每秒...

    红蜘蛛多媒体网络教室v7.0版(build 1189)

    采用全新视频驱动核心、MMX/SSE/SSE2指令和多级缓存技术,极大地提高屏幕广播速度和性能, 对3D、游戏、电影、多媒体课件、动画、DVD视频、FLASH、POWERPOINT等都能非常流畅地没有任何延迟地进行广播,甚至达到每秒...

    红蜘蛛多媒体网络教室v7.2版 build 1208

    采用全新视频驱动核心、MMX/SSE/SSE2指令和多级缓存技术,极大地提高屏幕广播速度和性能, 对3D、游戏、电影、多媒体课件、动画、DVD视频、FLASH、POWERPOINT等都能非常流畅地没有任何延迟地进行广播,甚至达到每秒...

    红蜘蛛多媒体网络教室v6.8版

    采用全新视频驱动核心、MMX/SSE/SSE2指令和多级缓存技术,极大地提高屏幕广播速度和性能,对3D、游戏、电影、多媒体课件、动画、DVD视频、FLASH、POWERPOINT等都能非常流畅地没有任何延迟地进行广播,甚至达到每秒30...

    红蜘蛛多媒体网络教室安装包和破解补丁

    采用全新视频驱动核心、MMX/SSE/SSE2指令和多级缓存技术,极大地提高屏幕广播速度和性能,对3D、游戏、电影、多媒体课件、动画、DVD视频、FLASH、POWERPOINT等都能非常流畅地没有任何延迟地进行广播,甚至达到每秒30...

    红蜘蛛教师系统

    采用全新视频驱动核心、MMX/SSE/SSE2指令和多级缓存技术,极大地提高屏幕广播速度和性能,对3D/游戏/电影/多媒体课件/动画/DVD视频/FLASH/POWERPOINT等都能非常流畅地没有任何延迟地进行广播,达到每秒30帧的速度;...

Global site tag (gtag.js) - Google Analytics