OpenGL除了颜色缓冲区、深度缓冲区、模板缓冲区以外,还有累积缓冲区。累积缓冲区容许你把渲染到颜色缓冲区的值,拷贝到累积缓冲区。在屡次拷贝操做到累积缓冲区时,能够用不一样方式的把颜色缓冲区内容和当前累积缓冲区的内容进行重复混合。当在累积缓冲区完成一幅图像以后,能够拷回颜色缓冲区,而后经过SwapBuffers显示到屏幕上。函数
累积缓冲区的操做经过void glAccum(GLenum op, GLfloat value);控制。第一个参数表示对累积缓冲区所进行的操做。第二个参数是浮点数用于指定缩放因子。oop
OpenGL支持的累积缓冲区的操做以下表:性能
操做 | 描述 |
GL_ACCUM | 把颜色缓冲区的颜色值进行缩放后,累加到累积缓冲区 |
GL_LOAD | 把颜色缓冲区的颜色值进行缩放后,替换掉累积缓冲区的颜色值 |
GL_RETURN | 把累积缓冲区的颜色值缩放后,拷贝回颜色缓冲区 |
GL_MULT | 把累积缓冲区的颜色值缩放后,替换掉原累积缓冲区的颜色值 |
GL_ADD | 把累积缓冲区的颜色值缩放后,累加到累积缓冲区 |
因为累积缓冲区会带来大内存的开销,因此在实时应用程序中比较少用。但在非实时的应用程序中,能够产生实时应用程序没法作到的效果。例如,你能够屡次渲染场景,并在每次渲染时进行抖动零点几个像素,这样就能够产生整个场景的反走样的效果,比多重采样的效果还要好。还能够模糊前景或背景,而后清晰的渲染一个物体来模拟,照相机景深的效果。测试
下面的例子是一个球体在地板上滚动,运动模糊的效果。spa
#include "gltools.h"
GLfloat fLightPos[4] = { -100.0f, 100.0f, 50.0f, 1.0f };
GLfloat fNoLight[] = { 0.0f, 0.0f, 0.0f, 0.0f };
GLfloat fLowLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };
GLfloat fBrightLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat yRot;
void DrawGround()
{
GLfloat fExtent = 20.0f;
GLfloat y = -0.0f;
GLfloat step = 0.5f;
GLfloat x, z;
int iColor = 0;
glShadeModel(GL_FLAT);
for (x = -fExtent; x <= fExtent; x += step)
{
glBegin(GL_TRIANGLE_STRIP);
for (z = fExtent; z >= -fExtent; z -= step)
{
if ((iColor % 2) == 0)
{
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
}
else
{
glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
}
glVertex3f(x, y, z);
glVertex3f(x + step, y, z);
iColor++;
}
glEnd();
}
glShadeModel(GL_SMOOTH);
}
void DrawGemometry()
{
glPushMatrix();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DrawGround();
glColor3f(1.0f, 0.0f, 0.0f);
glTranslatef(0.0f, 0.3f, -3.5f);
glRotatef(-yRot*2.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(1.0f, 0.0f, 0.0f);
glutSolidSphere(0.1f, 17, 13);
glPopMatrix();
}
void RenderScene()
{
yRot = 35.0f;
GLfloat pass = 10.0f;
for (int i = 0; i < 10; ++i)
{
yRot += 0.75f;
DrawGemometry();
//复制到累积缓冲区
if (i == 0)
{
glAccum(GL_LOAD, 0.5f);
}
else
{
//累加到累积缓冲区
glAccum(GL_ACCUM, (0.5f * 1 / pass));
}
}
glAccum(GL_RETURN, 1.0f);
glutSwapBuffers();
}
void ChangeSize(GLsizei w, GLsizei h)
{
if (h == 0)
h = 1;
glViewport(0, 0, w, h);
GLfloat faspect = (GLfloat)w/(GLfloat)h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(35.0f, faspect, 1.0f, 50.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, -0.4f, 0.0f);
glutPostRedisplay();
}
void SetupRC()
{
glClearColor(0.25f, 0.25f, 0.25f, 1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
//设置光照
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fNoLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, fLowLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, fBrightLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight);
glLightfv(GL_LIGHT0, GL_POSITION, fLightPos);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//开启颜色追踪
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glMateriali(GL_FRONT, GL_SHININESS, 128);
}
int main(int args, char **argv)
{
glutInit(&args, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE | GLUT_ACCUM);
glutInitWindowSize(800, 600);
glutCreateWindow("motion blur");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
SetupRC();
glutMainLoop();
return 0;
}
DrawGeometry函数绘制了场景中的全部几何图元。在RenderScene中反复调用这个函数,并把结果累积到累积缓冲区中。在最后,拷贝回到颜色缓冲区,而后glutSwapBuffers显示到屏幕上:.net
在计算后的最终颜色将要写入到颜色缓冲区时,OpenGL容许你经过glColorMask函数来屏蔽掉其中的一个或多个通道值。code
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);内存
参数分别表明红、绿、蓝、alpha通道。当传的参数是GL_TRUE时,表示容许往这个通道的写值,若是为GL_FALSE则阻止往该通道写值。ci
许多2D的图形API容许源颜色和目的颜色进行逻辑操做。OpenGL也支持这种操做:get
void glLogicOp(GLenum op);
还须要经过glEnable(GL_COLOR_LOGIC_OP);来开启。OpenGL在默认状况下是关闭的。关闭操做是相应的glDisable
op容许的操做以下表:
参数值 | 操做 |
GL_CLEAR | 0 |
GL_AND | s & d |
GL_AND_REVERSE | s & ~d |
GL_COPY | s |
GL_AND_INVERTED | ~s & d |
NOOP | d |
XOR | s xor d |
OR | s | d |
NOR | ~(s | d) |
GL_EQUIV | ~(s xor d) |
GL_OR_REVERSE | s | ~d |
GL_COPY_INVERTED | ~s |
GL_OR_INVERTED | ~s | d |
GL_NAND | ~(s & d) |
SET | all 1s |
Alpha 测试
Alpha测试容许你告诉OpenGL那些在Alpha测试不经过的输入片断将被废弃。那些被废弃的片断不会写入到颜色缓冲区,深度缓冲区,模板缓冲区和累积缓冲区中。那些alpha值很低的片断多是不可见的,所以咱们能够过滤掉它,不写入到缓冲区中,能够提升性能。
alpha测试值和比较函数能够经过glAlphaFunc指定:
void glAlphaFunc(GLenum func, GLclampf ref);
ref的取值范围为[0.0, 1.0].能够指定的比较方式以下表:
比较方式 | 描述 |
GL_NEVER | 永远不经过 |
GL_ALWAYS | 一直经过 |
GL_LESS | 小于ref |
GL_LEQUAL | 小于等于ref |
GL_EQUAL | 等于ref |
GL_GEQUAL | 大于等于ref |
GL_GREATER | 大于ref |
GL_NOTEQUAL | 不等于ref |
行为与glDepthFunc函数类似。能够经过glEnable/glDisable来开启和关闭alpha测试,参数值是GL_ALPHA_TEST。
抖动容许只有少许离散颜色的显示系统来模拟更宽范围的颜色。例如,灰色能够经过白点和黑点的混合来模拟。白点多于黑点呈现浅灰色,黑点多于白点呈现深灰色。这种技巧对于只支持8位和16位的显示系统很是有用。抖动的效果能够大幅度地改善低端颜色系统的图像质量。在默认状况下,抖动是打开的。能够经过glEnable(GL_DITHER)/glDisable(GL_DITHER)来打开或关闭它。在高颜色分辨率的显示系统中,OpenGL的实现可能不须要抖动,会禁用抖动来避免性能的开销。