荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Peter (小飞侠), 信区: Program
标  题: OPENGL(18)
发信站: BBS 荔园晨风站 (Fri Jan 22 08:22:12 1999), 转信


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 "glos.h"
#include <GL/gl.h>
#include <GL/glaux.h>
#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!!!实现当初提出的“长长见识”的设想。
今后有什么新内容我还会尽量补充,大家也可以自由补充。

--
※ 来源:.BBS 荔园晨风站 bbs.szu.edu.cn.[FROM: 192.168.1.3]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店