在正常狀況下,OpenGL渲染時會把顏色值輸入到顏色緩衝區中,深度值輸入到深度緩衝區中。若是咱們關閉深度測試,那麼新的顏色值會簡單地覆蓋已經存在於顏色緩衝區中的值。當開啓深度測試時,顏色段只有在經過深度測試時,纔會覆蓋已經存在於顏色緩衝區中的值。在這兩種狀況下,在渲染時顏色值要麼徹底被廢棄,要麼就直接覆蓋舊的顏色值。如今介紹一種新的方式,混合。函數
glEnable(GL_BLEND);oop
當開啓混合時,輸入的顏色值將會和已經存在於顏色緩衝區中的顏色進行組合。至於如何進行組合,取決於你爲混合設置的參數。測試
首先須要瞭解兩個概念:spa
當開啓OpenGL的混合時,源顏色是如何與目標顏色進行結合的,取決於你設置的混合方程式。默認狀況下的,混合方程以下:.net
Ci = (Cs * S) + (Cd * D)3d
在這裏,Ci是最終被計算出來的顏色,Cs是源顏色,Cd是目標顏色。而S和D分別是源混合因子和目標混合因子。這些混合因子經過:glBlendFunc(GLenum S, GLenum D);設置。S和D是枚舉值,其枚舉列表以下:(R、G、B、A分別表明紅色成分,綠色成分,藍色成分,Alpha成分)code
Function | RGB Blend Factors | Alpha Blend Factor |
GL_ZERO | (0,0,0)ip |
0 |
GL_ONE | (1,1,1) | 1 |
GL_SRC_COLOR | (Rs ,Gs ,Bs) | As |
GL_ONE_MINUS_SRC_COLOR | (1,1,1)-(Rs,Gs ,Bs) | 1-As |
GL_DST_COLOR | (Rd,Gd ,Bd) | Ad |
GL_ONE_MINUS_DST_COLOR | (1,1,1)-(Rd,Gd ,Bd) | 1-Ad |
GL_SRC_ALPHA | (As ,As,As ) | As |
GL_ONE_DST_ALPHA | (Ad ,Ad,Ad ) | Ad |
GL_ONE_MINUS_DST_ALPHA | (1,1,1)-(Ad ,Ad,Ad ) | 1-Ad |
GL_CONSTANT_COLOR | (Rc,Gc,Bc) | Ac |
GL_ONE_MINUS_CONST_COLOR | (1,1,1)-(Rc,Gc,Bc) | 1-Ac |
GL_CONST_ALPHA | (Ac,Ac,Ac) | Ac |
GL_ONE_MINUS_CONSTANT_ALPHA | (1,1,1)-(Ac,Ac,Ac) | 1-Ac |
GL_SRC_ALPHA_SATURATE | (f,f,f)* | 1 |
* f = min(A s , 1 – A d)
PS:上面表格的顏色值都是用浮點數來表示的。舉例說明:ci
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);get
經過上面的調用來告訴OpenGL咱們使用的混合因子。假設如今渲染命令傳進來的源RGBA顏色值是(1.0f,0.0f,1.0f,1.0f).而在顏色緩衝區相同的位置已經有目標顏色RGBA值是(0.0f, 1.0f, 0.0f, 1.0f).
代入公式:Ci = (Cs * S) + (Cd * D)
Cs=(1.0f,0.0f,1.0f,0.6f), GL_SRC_ALPHA參數說明源混合因子取源顏色的alpha值,因此 S = 0.6f。Cd=(0.0f, 1.0f, 0.0f, 1.0f). GL_ONE_MINUS_SRC_ALPHA說明了目標混合因子取1-As,D = 1-0.6 = 0.4f;
因此代入計算得(Cs * S) = (0.6f, 0.0f, 0.6f, 0.36f) , (Cd * D) = (0.0f, 0.4f, 0.0f, 0.4f)
Ci = (Cs * S) + (Cd * D) = (0.6f, 0.4f, 0.6f, 0.76f)
獲得的顏色是近似於洋紫色。
上面表格的GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR,GL_CONSTANT_ALPHA和GL_ONE_MINUS_CONSTANT_ALPHA的值在默認狀況下是(0.0f, 0.0f, 0.0f, 0.0f)但咱們能夠經過下面的函數修改:
void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
顏色混合常常用於在不透明的前面畫一個透明的物體。這樣咱們就能夠先畫好背景,而後再在上面畫一個半透明的物體。能夠製造一種,透過彩色玻璃看外面的風景的效果。下面的例子:(物體在光滑的彩色地面上的倒影)。
#include "gltools.h"
#include "math3d.h"
//光源位置
GLfloat lightPos[4] = { -100.0f, 100.0f, 50.0f, 1.0f };
GLfloat lightPosMirror[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 };
void DrawGround()
{
//畫地面
GLfloat fExtent = 20.0f;
GLfloat fStep = 0.5f;
GLfloat y = 0.0f;
GLfloat fColor;
GLfloat iStrip, iRun;
GLint iBounce = 0;
glShadeModel(GL_FLAT);
for(iStrip = -fExtent; iStrip <= fExtent; iStrip += fStep)
{
glBegin(GL_TRIANGLE_STRIP);
for(iRun = fExtent; iRun >= -fExtent; iRun -= fStep)
{
if((iBounce %2) == 0)
fColor = 1.0f;
else
fColor = 0.0f;
glColor4f(fColor, fColor, fColor, 0.5f);
glVertex3f(iStrip, y, iRun);
glVertex3f(iStrip + fStep, y, iRun);
iBounce++;
}
glEnd();
}
glShadeModel(GL_SMOOTH);
}
void DrawWorld()
{
glColor3f(1.0f, 0.0f, 0.0f);
glPushMatrix();
glTranslatef(0.0f, 0.5f, -3.5f);
gltDrawTorus(0.25, 0.08, 68, 37);
glPopMatrix();
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glPushMatrix();
//設置光源的倒影
glLightfv(GL_LIGHT0, GL_POSITION, lightPosMirror);
glPushMatrix();
//由於是鏡像,因此要反過來繪製
glFrontFace(GL_CW);
glScalef(1.0f, -1.0f, 1.0f);
DrawWorld();
glFrontFace(GL_CCW);
glPopMatrix();
//畫地面時,關閉光源, 地面可見並均勻着色。
glDisable(GL_LIGHTING);
//打開混合,設置混合因子
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//畫地面
DrawGround();
//關閉混合效果
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
glPopMatrix();
//設置光源在左上角
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
DrawWorld();
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.0, faspect, 1.0f, 50.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//往Y軸負方向平移一點
glTranslatef(0.0f, -0.4f, 0.0f);
glutPostRedisplay();
}
void SetupRC()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//開啓深度測試,剔除物體背面
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
//逆時針方向繪製的面爲正面
glFrontFace(GL_CCW);
//開啓光照,設置光源參數
glEnable(GL_LIGHTING);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fNoLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, fLowLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, fBrightLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, fBrightLight);
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_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("Reflection");
glutDisplayFunc(RenderScene);
glutReshapeFunc(ChangeSize);
SetupRC();
glutMainLoop();
return 0;
}
OpenGL的默認混合方程式:Ci = (Cs * S) + (Cd * D)
但咱們能夠經過函數:
void glBlendEquation(GLenum mode);
來改變混合方程。可選擇的混合方程模式以下表:
還有一個更靈活的函數:
void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
這個函數容許你分別指定RGB的混合方程和alpha成分的混合方程。