歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

OpenGL超級寶典學習筆記——混合

混合

在正常情況下,OpenGL渲染時會把顏色值輸入到顏色緩沖區中,深度值輸入到深度緩沖區中。如果我們關閉深度測試,那麼新的顏色值會簡單地覆蓋已經存在於顏色緩沖區中的值。當開啟深度測試時,顏色段只有在通過深度測試時,才會覆蓋已經存在於顏色緩沖區中的值。在這兩種情況下,在渲染時顏色值要麼完全被廢棄,要麼就直接覆蓋舊的顏色值。現在介紹一種新的方式,混合。

glEnable(GL_BLEND);

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

 

組合顏色

首先需要了解兩個概念:

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

當開啟OpenGL的混合時,源顏色是如何與目標顏色進行結合的,取決於你設置的混合方程式。默認情況下的,混合方程如下:

Ci = (Cs * S) + (Cd * D)

在這裡,Ci是最終被計算出來的顏色,Cs是源顏色,Cd是目標顏色。而S和D分別是源混合因子和目標混合因子。這些混合因子通過:glBlendFunc(GLenum S, GLenum D);設置。S和D是枚舉值,其枚舉列表如下:(R、G、B、A分別代表紅色成分,綠色成分,藍色成分,Alpha成分)

Function RGB Blend Factors Alpha Blend Factor GL_ZERO

(0,0,0)

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:上面表格的顏色值都是用浮點數來表示的。舉例說明:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

通過上面的調用來告訴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成分的混合方程。

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

Copyright © Linux教程網 All Rights Reserved