【转】单缓冲与双缓冲的区别

摘自:http://zhidao.baidu.com/question/145477958.html

OpenGL单缓冲与双缓冲的区别(追加10分)

最佳答案

单缓冲,实际上就是将所有的绘图指令在窗口上执行,就是直接在窗口上绘图,这样的绘图效率是比较慢的,如果使用单缓冲,而电脑比较慢,你回到屏幕的闪烁。

双缓冲,实际上的绘图指令是在一个缓冲区完成,这里的绘图非常的快,在绘图指令完成之后,再通过交换指令把完成的图形立即显示在屏幕上,这就避免了出现绘图的不完整,同时效率很高。

一般用OpenGL绘图都是用双缓冲,单缓冲一般只用于显示单独的一副非动态的图像

 

 

http://thatax.blog.163.com/blog/static/20892680200871242445116/

 

OpenGL的消隐与双缓冲

2008-08-12 16:24:45| 分类: OpenGL | 标签: |字号大中小 订阅

首先是大家可能已经发现,在我们之前提到的所有例子中,在图形的旋转过程中整个图形都有一定程度的闪烁现象,显得图形的过渡极不平滑,这当然不是我们所要的效果,幸好opengl 支 持一个称为双缓存的技术,可以有效的帮助我们解决这个问题。我们知道在我们电脑中,屏幕中显示的东西都会被放在一个称为显示缓存的地方,在通常情况下我们 只有一个这样的缓冲区,也就是单缓冲,在单缓冲中任何绘图的过程都会被显示在屏幕中,这也就是我们为什么会看到闪烁,而所谓双缓冲就是再这个显示的缓冲区 之外再建立一个不显示的缓冲区,我们所有的绘图都将在这个不显示的缓冲区中进行,只有当一帧都绘制完了之后才会被拷贝到真正的现实缓冲区显示出来,这样中间过程对于最终用户就是不可见的了,那即使是速度比较慢也只会出现停顿而不会有闪烁的现象出现。

在OpenGL 中我们可以通过glut 库中的函数

void glutSwapBuffers(void) 来实现从非显示缓冲区到显示缓冲区的复制

当然在使用双缓冲之前我们也要在 glutInitDisplayMode设定参数的时候选择GLUT_DOUBLE 而不是之前我们用的 GLUT_SINGLE 相信这两个参数的意思也应该很明白了

在解决了闪烁的问题之后我们来解决另一个问题首先我们在窗口中画两个交叉的分别位于ZOX 和 ZOY 平面的长方形并用不同的颜色填充它们,然后让它们旋转很快我们发现有个比较严重的问题发生了,因为我们发现opengl显然没有空间的位置观念因为它根本不能分辨物体的前后关系,当然也不能做出适当的显示,在opengl中我们使用深度缓冲区来解决这个问题,在这个缓冲区中存放着每个象素深度信息,当有一个新的象素需要显示的时候,我们可以通过一个被称为深度测试的函数来确定它们的先后关系,要使用深度缓冲区有以下几个步骤:

1.在函数 glutInitDisplayMode(mode) 中将GLUT_DEPTH置位表明要使用深度缓冲区

2.使用函数glEnable(GL_DEPTH_TEST) 打开深度测试函数

void glEnable(GLenum cap);

void glDisable(GLenum cap);

这两个函数属于基本状态管理函数用来打开和关闭一些常用的功能,常用的参数有以下几个

GL_BLENDGL_DEPTH_TEST GL_FOG GL_LINE_STIPPLE GL_LIGHTING

3.是用函数glDepthFunc()来设置深度测试函数

void glDepthFunc(GLenum func)

这里我们比较常用的深度测试函数有 GL_LESS 和GL_LEQUAL 两者的区别在于当深度相同时是显示新的象素还是老的象素

4.使用下面的函数来设置深度缓冲区的值

void glClearDepth(GLclampd depth)

这里的参数是背景的深度一般来说我们都将背景深度设成最大值1

5. 最后在我们使用glClear(bits) 刷新背景的同时我们要将GL_DEPTH_BUFFER_BIT置位表示我们在刷新背景颜色的同时用刷新背景深度

#include "stdafx.h"

#include <math.h>

#include <gl/glut.h>

#include <gl/gl.h>

bool mouseisdown=false;

bool loopr=false;

int mx,my;

int ry=30;

intrx=30;

void timer(int p)

{

ry-=5;

glutPostRedisplay();

if (loopr)

glutTimerFunc(200,timer,0);

}

void mouse(int button, int state, int x, int y)

{

if(button == GLUT_LEFT_BUTTON)

{

if(state == GLUT_DOWN)

{ mouseisdown=true;loopr=false;}

else

mouseisdown=false;

}

if (button== GLUT_RIGHT_BUTTON)

if(state == GLUT_DOWN)

{loopr=true;glutTimerFunc(200,timer,0);}

}

void motion(int x, int y)

{

if(mouseisdown==true)

{

ry+=x-mx;

rx+=y-my;

mx=x;

my=y;

glutPostRedisplay();

}

}

void special(int key, int x, int y)

{

switch(key)

{

case GLUT_KEY_LEFT:

ry-=5;

glutPostRedisplay();

break;

case GLUT_KEY_RIGHT:

ry+=5;

glutPostRedisplay();

break;

case GLUT_KEY_UP:

rx+=5;

glutPostRedisplay();

break;

case GLUT_KEY_DOWN:

rx-=5;

glutPostRedisplay();

break;

}

}

void init()

//设置OpenGL的一些状态变量的初始值

{

glEnable(GL_DEPTH_TEST); //深度测试

glDepthFunc(GL_LESS); //设置深度测试函数

glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); //设置多边形显示模式为正反面都是填充显示

glClearColor(1,1,1,1); //设置刷新背景色

glClearDepth(1); //设置清除深度缓冲区所用的值

}

void display()

{

float red[3]={1,0,0};

float blue[3]={0,1,0};

float green[3]={0,0,1};

float yellow[3]={1,1,0};

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glRotatef(ry,0,1,0);

glRotatef(rx,1,0,0);

glBegin(GL_QUADS);

glColor3fv(green);

glVertex3f(0.5,0.5,0);

glVertex3f(-0.5,0.5,0);

glVertex3f(-0.5,-0.5,0);

glVertex3f(0.5,-0.5,0);

glEnd();

glBegin(GL_QUADS);

glColor3fv(red);

glVertex3f(0.5,0.5,0.3);

glVertex3f(-0.5,0.5,-0.3);

glVertex3f(-0.5,-0.5,-0.3);

glVertex3f(0.5,-0.5,0.3);

glEnd();

glBegin(GL_QUADS);

glColor3fv(yellow);

glVertex3f(0.5,0.5,-0.3);

glVertex3f(-0.5,0.5,0.3);

glVertex3f(-0.5,-0.5,0.3);

glVertex3f(0.5,-0.5,-0.3);

glEnd();

glFlush();

glutSwapBuffers();

}

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGBA|GLUT_DEPTH); //设置显示模式:单缓冲区, RGBA颜色模式

glutInitWindowSize (400, 400); //设置窗口宽度、高度

glutInitWindowPosition(100,100); //设置窗口位置

glutCreateWindow ("double"); //弹出窗口

init();

glutDisplayFunc (display); //设置窗口刷新的回调函数

glutMouseFunc(mouse); //设置鼠标器按键回调函数

glutMotionFunc(motion);

glutSpecialFunc(special);

glutMainLoop(); //开始主循环

return 0;

}

原文地址:https://www.cnblogs.com/lzhitian/p/2809434.html