OpenGL超級寶典筆記——混合

混合

在正常狀況下,OpenGL渲染時會把顏色值輸入到顏色緩衝區中,深度值輸入到深度緩衝區中。若是咱們關閉深度測試,那麼新的顏色值會簡單地覆蓋已經存在於顏色緩衝區中的值。當開啓深度測試時,顏色段只有在經過深度測試時,纔會覆蓋已經存在於顏色緩衝區中的值。在這兩種狀況下,在渲染時顏色值要麼徹底被廢棄,要麼就直接覆蓋舊的顏色值。如今介紹一種新的方式,混合。函數

glEnable(GL_BLEND);oop

當開啓混合時,輸入的顏色值將會和已經存在於顏色緩衝區中的顏色進行組合。至於如何進行組合,取決於你爲混合設置的參數。測試

組合顏色

首先須要瞭解兩個概念:spa

  • 目標顏色:已經存在於顏色緩衝區中的顏色值。這個顏色包含紅、綠、藍三種成分,和可選的alpha值。
  • 源顏色:來自於渲染命令的顏色。包含紅、綠、藍和可選的alpha值成分。

當開啓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;
}

image

改變混合方程

OpenGL的默認混合方程式:Ci = (Cs * S) + (Cd * D)

但咱們能夠經過函數:

void glBlendEquation(GLenum mode);

來改變混合方程。可選擇的混合方程模式以下表:

image

還有一個更靈活的函數:

void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);

這個函數容許你分別指定RGB的混合方程和alpha成分的混合方程。

相關文章
相關標籤/搜索