日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OPenGL 颜色混合(Blending)

發(fā)布時(shí)間:2023/12/15 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OPenGL 颜色混合(Blending) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

寫在前面
上一節(jié)學(xué)習(xí)了使用模板緩沖來制作特殊效果,本節(jié)將繼續(xù)學(xué)習(xí)一個(gè)高級主題-混色(Blending)。通過使用混色,我們可以制作透明、半透明效果。本節(jié)示例代碼均可以在我的github下載。

本節(jié)內(nèi)容整理自www.learnopengl.com blending.

混色的概念
所謂混色,就是將當(dāng)前要繪制的物體的顏色和顏色緩沖區(qū)中已經(jīng)繪制了的物體的顏色進(jìn)行混合,最終決定了當(dāng)前物體的顏色。例如下面的圖中,狙擊槍的瞄準(zhǔn)器本身是帶有藍(lán)色的,將它和后面的任務(wù)混合在一起,形成了我們看到的最終效果,這個(gè)效果里既有瞄準(zhǔn)器的藍(lán)色成分,也有后面人物的像素,主要是后面人物的像素。
?

實(shí)際上我們通過玻璃看到外面的景象就是一種混色,有的玻璃完全透明則主要顯示外面的景象,而另一些玻璃不是完全透明則成像中包含一部分玻璃的顏色。在OpenGL中使用混色,可以實(shí)現(xiàn)很多效果,其中比較常見的就是透明效果。下面具體實(shí)現(xiàn)完全透明和半透明效果。

完全透明效果
完全透明表現(xiàn)的是,當(dāng)前物體例如透明玻璃,將后面的像素完全展示出來,而當(dāng)前物體則不必顯示。實(shí)現(xiàn)完全透明效果,我們通過對物體的透明度進(jìn)行判斷,當(dāng)小于一定閾值,例如0.1時(shí),我們則丟棄該片元,使其后面的片元得到顯示。
首先我們加載一個(gè)草的模型,對于草這種模型,它要么完全透明,可以透過它看到后面的物體,要么不透明展示為草的細(xì)節(jié)。繪制草這種模型時(shí),我們通過往矩形塊上添加草的紋理來實(shí)現(xiàn)。加載了草的模型,使用深度測試一節(jié)的立方體,繪制出來的效果如下:

這里我們看到,草模型中透明部分和不透明部分沒有得到區(qū)分,因而擋住了后面的立方體和草模型。在RGBA表達(dá)的顏色重,alpha成分一直以來,我們都是設(shè)置為1.0,實(shí)際上這個(gè)分量表達(dá)的就是透明度。1.0表示為完全不透明,0.0則表示完全透明。我們可以根據(jù)加載的草模型的alpha值判斷是否應(yīng)該丟棄片元來實(shí)現(xiàn)透明效果。

加載RGBA模型,和之前一直實(shí)現(xiàn)的加載RGB模型,有少許不同,我們要注意兩點(diǎn):

使用SOIL庫的時(shí)候參數(shù)要從SOIL_LOAD_RGB改為SOIL_LOAD_RGBA

glTexImage2D中圖片格式和內(nèi)部表示要從GL_RGB改為GL_RGBA.

glTexParameteri紋理的wrap方式需要從GL_REPEAT改為GL_CLAMP_TO_EDGE,這個(gè)主要是為了防止由于使用GL_REPEAT時(shí)紋理邊緣部分插值導(dǎo)致出現(xiàn)我們不需要的半透明的效果

加載紋理的函數(shù)聲明為:
?

static GLuint load2DTexture(const char* filename, GLint internalFormat = GL_RGB,GLenum picFormat = GL_RGB, int loadChannels = SOIL_LOAD_RGB, GLboolean alpha=false);

?完整的實(shí)現(xiàn)可以參考texture.h。

在代碼中加載紋理變更為:

GLuint transparentTextId =TextureHelper::load2DTexture( "grass.png", GL_RGBA, GL_RGBA, SOIL_LOAD_RGBA, true);

在片元著色器中,根據(jù)alpha值是否小于設(shè)定的閾值,我們決定是否丟棄片元:

#version 330 core in vec2 TextCoord; uniform sampler2D text; out vec4 color; void main() {vec4 textColor = texture(text, TextCoord);if(textColor.a < 0.1) // < 0.1則丟棄片元 discard;color = textColor; }

這種方法實(shí)現(xiàn)的透明效果如下圖所示:

使用alpha值決定是否丟棄片元,我們實(shí)現(xiàn)的透明效果是要么完全透明(alpha <0.1),要么不透明(alpha >= 0.1)。實(shí)際應(yīng)用中還需要使用半透明效果。

OpenGL中混色計(jì)算
混色后可以通過當(dāng)前物體看到其后的物體,這里當(dāng)前物體的最終顏色是由當(dāng)前物體的顏色(源的顏色 source color)和顏色緩沖區(qū)中的顏色(目的顏色 destination color)混色決定的,也就是進(jìn)行相應(yīng)的混合計(jì)算得到的。

要開啟混色功能需要使用:

glEnable(GL_BLEND);

混色是計(jì)算出來的,主體的公式是這樣的:

Result=source?sfactor+destination?dfactor? ? ? ? ? ? ? ? ? ? ? ?(1)

公式1中source和destination表示的分別是源和目的顏色,sFactor 和dFactor分別表示源和目的顏色的計(jì)算系數(shù)。
用戶可以靈活的控制公式1的sFactor 和dFactor ,上式計(jì)算是逐個(gè)顏色分量RGBA計(jì)算的。

OpenGL提供了函數(shù)glBlendFunc用來設(shè)置上面的sfactor和dfactor,函數(shù)原型為:

API void glBlendFunc( GLenum sfactor, GLenum dfactor);
sfactor和dfactor用來指定源和目的顏色計(jì)算的系數(shù),使用的是GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR等枚舉值。
例如,一個(gè)紅色和綠色方塊進(jìn)行混色,效果如下圖所示:

這里綠色(0.0,1.0,0.0,0.6)作為源,紅色(1.0,0.0,0.0,1.0)作為目的顏色進(jìn)行混合。我們設(shè)置參數(shù)為:

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

則進(jìn)行計(jì)算的過程為:

result=(0.0,1.0,0.0,0.6)?(0.6,0.6,0.6,0.6)+(1.0,0.0,0.0,1.0)?(0.4,0.4,0.4,0.4)=(0.4,0.6,0.0,0.76)result=(0.0,1.0,0.0,0.6)?(0.6,0.6,0.6,0.6)+(1.0,0.0,0.0,1.0)?(0.4,0.4,0.4,0.4)=(0.4,0.6,0.0,0.76)
除了glBlendFunc外,還可以使用使用glBlendFuncSeparate單獨(dú)指定RGB,Alpha的計(jì)算系數(shù)。

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

這里的參數(shù)同樣是GL_ZERO,GL_ONE,GL_SRC_COLOR等枚舉值。

另外,還可以通過glBlendEquation(GLenum mode);和glBlendEquationSeparate來指定源和目的顏色的計(jì)算方式,默認(rèn)是GL_FUNC_ADD,就是公式1所示的情況。例如GL_FUNC_SUBTRACT則對應(yīng)公式2:

Result=source?sfactor?destination?dfactor? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2)

一般我們使用的組合為:

glBlendEquation(GL_FUNC_ADD); // 默認(rèn),無需顯式設(shè)置glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

繪制半透明效果

上面介紹了OpenGL中混色的計(jì)算,下面實(shí)現(xiàn)一個(gè)半透明的效果。
通過加載一個(gè)半透明的窗戶到場景,使得透過窗戶可以看到后面的場景。我們的著色器恢復(fù)到:

#version 330 core in vec2 TextCoord; uniform sampler2D text; out vec4 color;void main() {color = texture(text, TextCoord); }

在場景中使用GL_RGBA等包含alpha的參數(shù)加載窗戶模型后,繪制窗戶時(shí)使用代碼:

for (std::vector<glm::vec3>::const_iterator it = windowObjs.begin();windowObjs.end() != it; ++it) {model = glm::mat4();model = glm::translate(model, *it);glUniformMatrix4fv(glGetUniformLocation(shader.programId, "model"),1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 6); }

得到效果如下圖所示:

上面的圖中,仔細(xì)看則會發(fā)現(xiàn)視覺bug,前面的窗戶看不到后面的窗戶。這主要是因?yàn)樯疃葴y試,并不關(guān)心alpha值,因此前面的窗戶由于里觀察者更近,擋住了后面的窗戶,因此后面的窗戶沒有顯示出來。
對于這一問題,需要考慮排序問題 Transparency Sorting。
繪制包含不透明和透明場景的順序?yàn)?#xff1a;

1.首先繪制不透明物體
2.對透明物體進(jìn)行排序
3.按照排序后的順序,繪制透明物體。

我們這里的解決方法是對窗戶進(jìn)行由遠(yuǎn)及近的繪制,那么在繪制近一些的窗戶時(shí),執(zhí)行混色,混合當(dāng)前顏色buffer中顏色(場景中處于后面的窗戶的顏色)和當(dāng)前要繪制的窗戶顏色,則能產(chǎn)生正常的結(jié)果。

這里使用的排序規(guī)則是,窗戶到觀察者的距離,借助c++ std::map默認(rèn)對鍵值進(jìn)行排序的功能排序,然后使用逆向迭代器迭代繪制即可,具體實(shí)現(xiàn)為:

// 繪制透明物體 // 根據(jù)到觀察者距離遠(yuǎn)近排序 使用map的鍵的默認(rèn)排序功能(鍵為整數(shù)時(shí)從小到大) std::map<GLfloat, glm::vec3> distanceMap; for (std::vector<glm::vec3>::const_iterator it = windowObjs.begin(); windowObjs.end() != it; ++it) {float distance = glm::distance(camera.position, *it);distanceMap[distance] = *it; } transparentShader.use(); glBindVertexArray(transparentVAOId); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, transparentTextId); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 根據(jù)transparency sort 結(jié)果進(jìn)行繪制 for (std::map<GLfloat, glm::vec3>::reverse_iterator it = distanceMap.rbegin(); distanceMap.rend() != it; ++it) {model = glm::mat4();model = glm::translate(model, it->second);glUniformMatrix4fv(glGetUniformLocation(shader.programId, "model"),1, GL_FALSE, glm::value_ptr(model));glDrawArrays(GL_TRIANGLES, 0, 6); } glDisable(GL_BLEND);

最終的半透明效果為:

最后的說明

本節(jié)介紹了使用混色功能繪制透明和半透明效果。注意在加載紋理時(shí),如果沒有將wrap方式從GL_REPEAT改為GL_CLAMP_TO_EDGE將會得到錯(cuò)誤的效果,如下圖所示:

同時(shí)本節(jié)在繪制半透明的窗戶時(shí),解決前后窗戶的視覺bug采用的排序規(guī)則是使用窗戶離觀察者的距離,這一方法并不適合所有的情形。實(shí)際在進(jìn)行Blend時(shí)解決這一個(gè)問題的方式是復(fù)雜的,感興趣地可以參考Transparency Sorting。同時(shí)混色也可以在指定的buffer上執(zhí)行,感興趣地可以參考OpenGL wiki Blending.
?
?
原文鏈接:https://blog.csdn.net/wangdingqiaoit/article/details/52264213

總結(jié)

以上是生活随笔為你收集整理的OPenGL 颜色混合(Blending)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。