青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

使用混合來實現半透明效果

今天介紹關于OpenGL混合的基本知識。混合是一種常用的技巧,通常可以用來實現半透明。但其實它也是十分靈活的,你可以通過不同的設置得到不同的混合結果,產生一些有趣或者奇怪的圖象。

混合是什么呢?混合就是把兩種顏色混在一起。具體一點,就是把某一像素位置原來的顏色和將要畫上去的顏色,通過某種方式混在一起,從而實現特殊的效果。
假設我們需要繪制這樣一個場景:透過紅色的玻璃去看綠色的物體,那么可以先繪制綠色的物體,再繪制紅色玻璃。在繪制紅色玻璃的時候,利用“混合”功能,把將要繪制上去的紅色和原來的綠色進行混合,于是得到一種新的顏色,看上去就好像玻璃是半透明的。
要使用OpenGL的混合功能,只需要調用:glEnable(GL_BLEND);即可。
要關閉OpenGL的混合功能,只需要調用:glDisable(GL_BLEND);即可。
注意:只有在RGBA模式下,才可以使用混合功能,顏色索引模式下是無法使用混合功能的。

一、源因子和目標因子
前面我們已經提到,混合需要把原來的顏色和將要畫上去的顏色找出來,經過某種方式處理后得到一種新的顏色。這里把將要畫上去的顏色稱為“源顏色”,把原來的顏色稱為“目標顏色”。
OpenGL會把源顏色和目標顏色各自取出,并乘以一個系數(源顏色乘以的系數稱為“源因子”,目標顏色乘以的系數稱為“目標因子”),然后相加,這樣就得到了新的顏色。(也可以不是相加,新版本的OpenGL可以設置運算方式,包括加、減、取兩者中較大的、取兩者中較小的、邏輯運算等,但我們這里為了簡單起見,不討論這個了)
下面用數學公式來表達一下這個運算方式。假設源顏色的四個分量(指紅色,綠色,藍色,alpha值)是(Rs, Gs, Bs, As),目標顏色的四個分量是(Rd, Gd, Bd, Ad),又設源因子為(Sr, Sg, Sb, Sa),目標因子為(Dr, Dg, Db, Da)。則混合產生的新顏色可以表示為:
(Rs*Sr+Rd*Dr, Gs*Sg+Gd*Dg, Bs*Sb+Bd*Db, As*Sa+Ad*Da)
當然了,如果顏色的某一分量超過了1.0,則它會被自動截取為1.0,不需要考慮越界的問題。

源因子和目標因子是可以通過glBlendFunc函數來進行設置的。glBlendFunc有兩個參數,前者表示源因子,后者表示目標因子。這兩個參數可以是多種值,下面介紹比較常用的幾種。
GL_ZERO:     表示使用0.0作為因子,實際上相當于不使用這種顏色參與混合運算。
GL_ONE:      表示使用1.0作為因子,實際上相當于完全的使用了這種顏色參與混合運算。
GL_SRC_ALPHA:表示使用源顏色的alpha值來作為因子。
GL_DST_ALPHA:表示使用目標顏色的alpha值來作為因子。
GL_ONE_MINUS_SRC_ALPHA:表示用1.0減去源顏色的alpha值來作為因子。
GL_ONE_MINUS_DST_ALPHA:表示用1.0減去目標顏色的alpha值來作為因子。
除此以外,還有GL_SRC_COLOR(把源顏色的四個分量分別作為因子的四個分量)、GL_ONE_MINUS_SRC_COLOR、GL_DST_COLOR、GL_ONE_MINUS_DST_COLOR等,前兩個在OpenGL舊版本中只能用于設置目標因子,后兩個在OpenGL舊版本中只能用于設置源因子。新版本的OpenGL則沒有這個限制,并且支持新的GL_CONST_COLOR(設定一種常數顏色,將其四個分量分別作為因子的四個分量)、GL_ONE_MINUS_CONST_COLOR、GL_CONST_ALPHA、GL_ONE_MINUS_CONST_ALPHA。另外還有GL_SRC_ALPHA_SATURATE。新版本的OpenGL還允許顏色的alpha值和RGB值采用不同的混合因子。但這些都不是我們現在所需要了解的。畢竟這還是入門教材,不需要整得太復雜~

舉例來說:
如果設置了glBlendFunc(GL_ONE, GL_ZERO);,則表示完全使用源顏色,完全不使用目標顏色,因此畫面效果和不使用混合的時候一致(當然效率可能會低一點點)。如果沒有設置源因子和目標因子,則默認情況就是這樣的設置。
如果設置了glBlendFunc(GL_ZERO, GL_ONE);,則表示完全不使用源顏色,因此無論你想畫什么,最后都不會被畫上去了。(但這并不是說這樣設置就沒有用,有些時候可能有特殊用途)
如果設置了glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);,則表示源顏色乘以自身的alpha值,目標顏色乘以1.0減去源顏色的alpha值,這樣一來,源顏色的alpha值越大,則產生的新顏色中源顏色所占比例就越大,而目標顏色所占比例則減小。這種情況下,我們可以簡單的將源顏色的alpha值理解為“不透明度”。這也是混合時最常用的方式。
如果設置了glBlendFunc(GL_ONE, GL_ONE);,則表示完全使用源顏色和目標顏色,最終的顏色實際上就是兩種顏色的簡單相加。例如紅色(1, 0, 0)和綠色(0, 1, 0)相加得到(1, 1, 0),結果為黃色。
注意:
所謂源顏色和目標顏色,是跟繪制的順序有關的。假如先繪制了一個紅色的物體,再在其上繪制綠色的物體。則綠色是源顏色,紅色是目標顏色。如果順序反過來,則紅色就是源顏色,綠色才是目標顏色。在繪制時,應該注意順序,使得繪制的源顏色與設置的源因子對應,目標顏色與設置的目標因子對應。不要被混亂的順序搞暈了。

二、二維圖形混合舉例
下面看一個簡單的例子,實現將兩種不同的顏色混合在一起。為了便于觀察,我們繪制兩個矩形:glRectf(-1, -1, 0.5, 0.5);glRectf(-0.5, -0.5, 1, 1);,這兩個矩形有一個重疊的區域,便于我們觀察混合的效果。
先來看看使用glBlendFunc(GL_ONE, GL_ZERO);的,它的結果與不使用混合時相同。

void myDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ZERO);

    glColor4f(1, 0, 0, 0.5);
    glRectf(-1, -1, 0.5, 0.5);
    glColor4f(0, 1, 0, 0.5);
    glRectf(-0.5, -0.5, 1, 1);

    glutSwapBuffers();
}


嘗試把glBlendFunc的參數修改為glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);以及glBlendFunc(GL_ONE, GL_ONE);,觀察效果。第一種情況下,效果與沒有使用混合時相同,后繪制的圖形會覆蓋先繪制的圖形。第二種情況下,alpha被當作“不透明度”,由于被設置為0.5,所以兩個矩形看上去都是半透明的,乃至于看到黑色背景。第三種是將顏色相加,紅色和綠色相加得到黃色。
http://blog.programfan.com/upfile/200704/20070406022726.jpghttp://blog.programfan.com/upfile/200704/20070406022731.jpghttp://blog.programfan.com/upfile/200704/20070406022735.jpg 

三、實現三維混合
也許你迫不及待的想要繪制一個三維的帶有半透明物體的場景了。但是現在恐怕還不行,還有一點是在進行三維場景的混合時必須注意的,那就是深度緩沖。
深度緩沖是這樣一段數據,它記錄了每一個像素距離觀察者有多近。在啟用深度緩沖測試的情況下,如果將要繪制的像素比原來的像素更近,則像素將被繪制。否則,像素就會被忽略掉,不進行繪制。這在繪制不透明的物體時非常有用——不管是先繪制近的物體再繪制遠的物體,還是先繪制遠的物體再繪制近的物體,或者干脆以混亂的順序進行繪制,最后的顯示結果總是近的物體遮住遠的物體。
然而在你需要實現半透明效果時,發現一切都不是那么美好了。如果你繪制了一個近距離的半透明物體,則它在深度緩沖區內保留了一些信息,使得遠處的物體將無法再被繪制出來。雖然半透明的物體仍然半透明,但透過它看到的卻不是正確的內容了。
要解決以上問題,需要在繪制半透明物體時將深度緩沖區設置為只讀,這樣一來,雖然半透明物體被繪制上去了,深度緩沖區還保持在原來的狀態。如果再有一個物體出現在半透明物體之后,在不透明物體之前,則它也可以被繪制(因為此時深度緩沖區中記錄的是那個不透明物體的深度)。以后再要繪制不透明物體時,只需要再將深度緩沖區設置為可讀可寫的形式即可。嗯?你問我怎么繪制一個一部分半透明一部分不透明的物體?這個好辦,只需要把物體分為兩個部分,一部分全是半透明的,一部分全是不透明的,分別繪制就可以了。
即使使用了以上技巧,我們仍然不能隨心所欲的按照混亂順序來進行繪制。必須是先繪制不透明的物體,然后繪制透明的物體。否則,假設背景為藍色,近處一塊紅色玻璃,中間一個綠色物體。如果先繪制紅色半透明玻璃的話,它先和藍色背景進行混合,則以后繪制中間的綠色物體時,想單獨與紅色玻璃混合已經不能實現了。
總結起來,繪制順序就是:首先繪制所有不透明的物體。如果兩個物體都是不透明的,則誰先誰后都沒有關系。然后,將深度緩沖區設置為只讀。接下來,繪制所有半透明的物體。如果兩個物體都是半透明的,則誰先誰后只需要根據自己的意愿(注意了,先繪制的將成為“目標顏色”,后繪制的將成為“源顏色”,所以繪制的順序將會對結果造成一些影響)。最后,將深度緩沖區設置為可讀可寫形式。
調用glDepthMask(GL_FALSE);可將深度緩沖區設置為只讀形式。調用glDepthMask(GL_TRUE);可將深度緩沖區設置為可讀可寫形式。
一些網上的教程,包括大名鼎鼎的NeHe教程,都在使用三維混合時直接將深度緩沖區禁用,即調用glDisable(GL_DEPTH_TEST);。這樣做并不正確。如果先繪制一個不透明的物體,再在其背后繪制半透明物體,本來后面的半透明物體將不會被顯示(被不透明的物體遮住了),但如果禁用深度緩沖,則它仍然將會顯示,并進行混合。NeHe提到某些顯卡在使用glDepthMask函數時可能存在一些問題,但可能是由于我的閱歷有限,并沒有發現這樣的情況。

那么,實際的演示一下吧。我們來繪制一些半透明和不透明的球體。假設有三個球體,一個紅色不透明的,一個綠色半透明的,一個藍色半透明的。紅色最遠,綠色在中間,藍色最近。根據前面所講述的內容,紅色不透明球體必須首先繪制,而綠色和藍色則可以隨意修改順序。這里為了演示不注意設置深度緩沖的危害,我們故意先繪制最近的藍色球體,再繪制綠色球體。
為了讓這些球體有一點立體感,我們使用光照。在(1, 1, -1)處設置一個白色的光源。代碼如下:
void setLight(void)
{
    static const GLfloat light_position[] = {1.0f, 1.0f, -1.0f, 1.0f};
    static const GLfloat light_ambient[]  = {0.2f, 0.2f, 0.2f, 1.0f};
    static const GLfloat light_diffuse[]  = {1.0f, 1.0f, 1.0f, 1.0f};
    static const GLfloat light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);
    glEnable(GL_DEPTH_TEST);
}
每一個球體顏色不同。所以它們的材質也都不同。這里用一個函數來設置材質。
void setMatirial(const GLfloat mat_diffuse[4], GLfloat mat_shininess)
{
    static const GLfloat mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f};
    static const GLfloat mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};

    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
    glMaterialfv(GL_FRONT, GL_EMISSION,  mat_emission);
    glMaterialf (GL_FRONT, GL_SHININESS, mat_shininess);
}
有了這兩個函數,我們就可以根據前面的知識寫出整個程序代碼了。這里只給出了繪制的部分,其它部分大家可以自行完成。
void myDisplay(void)
{
    // 定義一些材質顏色
    const static GLfloat red_color[] = {1.0f, 0.0f, 0.0f, 1.0f};
    const static GLfloat green_color[] = {0.0f, 1.0f, 0.0f, 0.3333f};
    const static GLfloat blue_color[] = {0.0f, 0.0f, 1.0f, 0.5f};

    // 清除屏幕
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 啟動混合并設置混合因子
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // 設置光源
    setLight();

    // 以(0, 0, 0.5)為中心,繪制一個半徑為.3的不透明紅色球體(離觀察者最遠)
    setMatirial(red_color, 30.0);
    glPushMatrix();
    glTranslatef(0.0f, 0.0f, 0.5f);
    glutSolidSphere(0.3, 30, 30);
    glPopMatrix();

    // 下面將繪制半透明物體了,因此將深度緩沖設置為只讀
    glDepthMask(GL_FALSE);

    // 以(0.2, 0, -0.5)為中心,繪制一個半徑為.2的半透明藍色球體(離觀察者最近)
    setMatirial(blue_color, 30.0);
    glPushMatrix();
    glTranslatef(0.2f, 0.0f, -0.5f);
    glutSolidSphere(0.2, 30, 30);
    glPopMatrix();

    // 以(0.1, 0, 0)為中心,繪制一個半徑為.15的半透明綠色球體(在前兩個球體之間)
    setMatirial(green_color, 30.0);
    glPushMatrix();
    glTranslatef(0.1, 0, 0);
    glutSolidSphere(0.15, 30, 30);
    glPopMatrix();

    // 完成半透明物體的繪制,將深度緩沖區恢復為可讀可寫的形式
    glDepthMask(GL_TRUE);

    glutSwapBuffers();
}

大家也可以將上面兩處glDepthMask刪去,結果會看到最近的藍色球雖然是半透明的,但它的背后直接就是紅色球了,中間的綠色球沒有被正確繪制。

http://blog.programfan.com/upfile/200704/20070406022744.jpghttp://blog.programfan.com/upfile/200704/20070406022749.jpg

小結:
本課介紹了OpenGL混合功能的相關知識。
混合就是在繪制時,不是直接把新的顏色覆蓋在原來舊的顏色上,而是將新的顏色與舊的顏色經過一定的運算,從而產生新的顏色。新的顏色稱為源顏色,原來舊的顏色稱為目標顏色。傳統意義上的混合,是將源顏色乘以源因子,目標顏色乘以目標因子,然后相加。
源因子和目標因子是可以設置的。源因子和目標因子設置的不同直接導致混合結果的不同。將源顏色的alpha值作為源因子,用1.0減去源顏色alpha值作為目標因子,是一種常用的方式。這時候,源顏色的alpha值相當于“不透明度”的作用。利用這一特點可以繪制出一些半透明的物體。
在進行混合時,繪制的順序十分重要。因為在繪制時,正要繪制上去的是源顏色,原來存在的是目標顏色,因此先繪制的物體就成為目標顏色,后來繪制的則成為源顏色。繪制的順序要考慮清楚,將目標顏色和設置的目標因子相對應,源顏色和設置的源因子相對應。
在進行三維混合時,不僅要考慮源因子和目標因子,還應該考慮深度緩沖區。必須先繪制所有不透明的物體,再繪制半透明的物體。在繪制半透明物體時前,還需要將深度緩沖區設置為只讀形式,否則可能出現畫面錯誤。

posted on 2009-01-03 05:45 RedLight 閱讀(2704) 評論(0)  編輯 收藏 引用 所屬分類: 3D渲染技術

<2008年4月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

導航

統計

公告


Name: Galen
QQ: 88104725

常用鏈接

留言簿(3)

隨筆分類

隨筆檔案

相冊

My Friend

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美专区在线播放| 亚洲欧洲日夜超级视频| 一区二区三区日韩精品视频| 久久亚洲二区| 亚洲欧美日韩精品综合在线观看 | 久久精品动漫| 亚洲综合色激情五月| 中文在线资源观看视频网站免费不卡| 在线 亚洲欧美在线综合一区| 国产精品亚洲美女av网站| 欧美日韩免费观看一区 | 亚洲性图久久| 亚洲毛片在线看| 一本一本久久a久久精品综合麻豆| 在线播放不卡| 亚洲视频精选在线| 香港成人在线视频| 久久在线免费视频| 欧美精品色网| 欧美日韩国内| 国产精品久久久久久久久久免费看| 欧美国产日韩在线| 国产精品欧美一区二区三区奶水| 国产精品美女久久久免费 | 亚洲伊人伊色伊影伊综合网| 午夜精品视频在线观看| 欧美激情视频一区二区三区不卡| 亚洲电影第1页| 亚洲资源在线观看| 久久中文字幕一区二区三区| 欧美日韩在线精品| 亚洲欧洲视频在线| 欧美xxx成人| 久久精品首页| 有码中文亚洲精品| 欧美成人精精品一区二区频| 亚洲人成在线播放| 久久综合久久综合久久综合| 欧美日韩亚洲一区二| 在线日韩欧美| 久久se精品一区精品二区| 亚洲肉体裸体xxxx137| 久久乐国产精品| 国产一区 二区 三区一级| 久久嫩草精品久久久精品| 久久综合给合| 亚洲精品视频在线看| 一区二区三区偷拍| 国产香蕉久久精品综合网| 99在线热播精品免费| 亚洲欧洲日本mm| 亚洲少妇中出一区| 国产精品qvod| 亚洲综合第一| 欧美一区亚洲| 亚洲免费成人av| 亚洲另类自拍| 国产模特精品视频久久久久 | 国产精品男女猛烈高潮激情 | 亚洲精品日韩精品| 一区二区三区四区五区精品| 国外视频精品毛片| 亚洲麻豆一区| 国产欧美一区二区色老头| 欧美成人国产一区二区| 国产精品久久久久久久久免费| 久久香蕉国产线看观看av| 欧美日韩日本国产亚洲在线| 免费亚洲一区| 国产日韩欧美日韩大片| 美日韩精品视频| 国产精品亚洲综合天堂夜夜| 亚洲日韩视频| 99精品国产热久久91蜜凸| 久久在精品线影院精品国产| 久久国产精品久久国产精品| 国产欧美视频一区二区| 亚洲精品视频二区| 亚洲精品日韩一| 欧美成人r级一区二区三区| 欧美77777| 亚洲欧美日韩视频一区| 亚洲自拍啪啪| 国产一区二区三区无遮挡| 欧美一区二区三区日韩视频| 欧美一级二区| 狠狠v欧美v日韩v亚洲ⅴ| 久久精品国产清自在天天线| 久久久精品日韩| 在线看一区二区| 欧美精品一区二区三区久久久竹菊 | 老妇喷水一区二区三区| 亚洲丰满在线| 欧美mv日韩mv国产网站| 久久久精品性| 中文日韩电影网站| 欧美日韩日本网| 久久av一区二区| 亚洲激情在线观看| 亚洲综合精品| 在线播放国产一区中文字幕剧情欧美| 欧美成人精品h版在线观看| 亚洲激情综合| 欧美日韩亚洲视频一区| 久久精品2019中文字幕| 亚洲国产精品一区二区尤物区| 亚洲一区在线视频| 亚洲欧美自拍偷拍| 亚洲精品乱码| 狠狠入ady亚洲精品| 黄色亚洲大片免费在线观看| 国产一区二区剧情av在线| 国产精品久久国产精麻豆99网站| 蜜桃av一区二区三区| 久久米奇亚洲| 欧美一区二区三区播放老司机| 一区二区三区欧美| 亚洲一区二区在线免费观看| 99re66热这里只有精品4| 亚洲国产综合在线| 91久久在线观看| 一本色道久久| 欧美一区二区三区另类| 久久九九99| 欧美 日韩 国产 一区| 日韩一级欧洲| 久久久午夜精品| 国产精品日韩一区二区三区| 在线观看亚洲| 欧美成人久久| 欧美一区二区高清| 欧美日韩一区二区欧美激情| 欧美成人午夜激情在线| 午夜精品福利在线| 欧美日韩一二三区| 亚洲黄色免费电影| 另类人畜视频在线| 久久精品论坛| 怡红院av一区二区三区| 欧美与黑人午夜性猛交久久久| 最新日韩精品| 在线观看一区二区精品视频| 美女黄毛**国产精品啪啪 | 国产精品一区免费视频| 国产偷久久久精品专区| 亚洲国产精品日韩| 亚洲尤物在线| 亚洲人成网在线播放| 午夜视频在线观看一区| 欧美激情影院| 激情久久久久| 欧美一区二区黄| 亚洲伦理在线| 欧美成人一区二区三区片免费| 国产午夜精品麻豆| 亚洲字幕在线观看| 亚洲高清资源| 久久精品国产91精品亚洲| 日韩视频久久| 欧美日韩精品欧美日韩精品一| 伊人婷婷欧美激情| 久久久人成影片一区二区三区 | 午夜亚洲性色福利视频| 亚洲第一精品福利| 免费观看久久久4p| 亚洲动漫精品| 日韩午夜在线视频| 国产精品久久97| 午夜宅男久久久| 久久精品99| 亚洲人成啪啪网站| 99精品视频网| 亚洲一区视频在线| 国产乱码精品一区二区三区忘忧草| 亚洲一区视频在线| 亚洲欧美日韩国产综合在线 | 亚洲狠狠丁香婷婷综合久久久| 老色鬼久久亚洲一区二区 | 9l国产精品久久久久麻豆| 男人天堂欧美日韩| 亚洲小视频在线观看| 午夜精品免费视频| 亚洲乱码国产乱码精品精| 午夜精品av| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 国产日韩亚洲欧美综合| 久热爱精品视频线路一| 欧美肥婆在线| 久久黄色小说| 欧美人与性动交a欧美精品| 久久黄金**| 正在播放欧美一区| 国产精品99久久久久久久女警 | 欧美在线地址| 亚洲在线观看免费视频| 欧美好吊妞视频| 亚洲成人在线视频播放 | 久久精品夜色噜噜亚洲aⅴ| 亚洲乱码国产乱码精品精| 欧美大片在线看|