OpenGL除了顏色緩沖區、深度緩沖區、模板緩沖區之外,還有累積緩沖區。累積緩沖區允許你把渲染到顏色緩沖區的值,拷貝到累積緩沖區。在多次拷貝操作到累積緩沖區時,可以用不同方式的把顏色緩沖區內容和當前累積緩沖區的內容進行重復混合。當在累積緩沖區完成一幅圖像之後,可以拷回顏色緩沖區,然後通過SwapBuffers顯示到屏幕上。
累積緩沖區的操作通過void glAccum(GLenum op, GLfloat value);控制。第一個參數表示對累積緩沖區所進行的操作。第二個參數是浮點數用於指定縮放因子。
OpenGL支持的累積緩沖區的操作如下表:
操作 描述 GL_ACCUM 把顏色緩沖區的顏色值進行縮放後,累加到累積緩沖區 GL_LOAD 把顏色緩沖區的顏色值進行縮放後,替換掉累積緩沖區的顏色值 GL_RETURN 把累積緩沖區的顏色值縮放後,拷貝回顏色緩沖區 GL_MULT 把累積緩沖區的顏色值縮放後,替換掉原累積緩沖區的顏色值 GL_ADD 把累積緩沖區的顏色值縮放後,累加到累積緩沖區由於累積緩沖區會帶來大內存的開銷,所以在實時應用程序中比較少用。但在非實時的應用程序中,可以產生實時應用程序無法做到的效果。例如,你可以多次渲染場景,並在每次渲染時進行抖動零點幾個像素,這樣就可以產生整個場景的反走樣的效果,比多重采樣的效果還要好。還可以模糊前景或背景,然後清晰的渲染一個物體來模擬,照相機景深的效果。
下面的例子是一個球體在地板上滾動,運動模糊的效果。
#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顯示到屏幕上:
在計算後的最終顏色將要寫入到顏色緩沖區時,OpenGL允許你通過glColorMask函數來屏蔽掉其中的一個或多個通道值。
void glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
參數分別代表紅、綠、藍、alpha通道。當傳的參數是GL_TRUE時,表示允許往這個通道的寫值,如果為GL_FALSE則阻止往該通道寫值。
許多2D的圖形API允許源顏色和目的顏色進行邏輯操作。OpenGL也支持這種操作:
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 1sAlpha 測試
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的實現可能不需要抖動,會禁用抖動來避免性能的開銷。
OpenGL超級寶典 第4版 中文版PDF+英文版+源代碼 見 http://www.linuxidc.com/Linux/2013-10/91413.htm
OpenGL編程指南(原書第7版)中文掃描版PDF 下載 http://www.linuxidc.com/Linux/2012-08/67925.htm
OpenGL 渲染篇 http://www.linuxidc.com/Linux/2011-10/45756.htm
Ubuntu 13.04 安裝 OpenGL http://www.linuxidc.com/Linux/2013-05/84815.htm
OpenGL三維球體數據生成與繪制【附源碼】 http://www.linuxidc.com/Linux/2013-04/83235.htm
Ubuntu下OpenGL編程基礎解析 http://www.linuxidc.com/Linux/2013-03/81675.htm
如何在Ubuntu使用eclipse for c++配置OpenGL http://www.linuxidc.com/Linux/2012-11/74191.htm
更多《OpenGL超級寶典學習筆記》相關知識 見 http://www.linuxidc.com/search.aspx?where=nkey&keyword=34581