徹底搞清楚pygame的blend mode

更新 發佈閱讀 8 分鐘

呼!折騰了好久,終於徹底搞清楚pygame的各個blend mode所用的計算式,到底是長啥樣子了。

在數位影像編輯和電腦圖學中,當不同的顏色混在一起時,最後會呈現出什麼顏色,完全取決於背後用的是怎樣的計算方式。不同的計算方式,就會得到不同的顏色,而blend mode就是指這些不同的計算方式。如果把blend mode翻譯成「混色模式」,應該可以讓人比較容易理解那到底是個什麼玩意兒。

在寫《The Nature of Code閱讀心得筆記——使用Python實作》《The Nature of Code閱讀心得與Python實作》第4.9節時,因為是有關於blend mode的內容,所以必須知道pygame在這部分有提供哪些功能,這樣才有辦法寫程式。讓人意想不到的是,明明內容不多,看來也都是些很簡單容易理解的概念,真正寫起程式來,卻老是做不出原書的效果,實在是讓人懷疑人生。

「啊你不會網路上查一下喔?!問一下AI也可以啊!」一定會有人帶著懷疑的眼神,以略帶不屑的口吻這樣說。是啦!是啦!這誰不知道啊?但問題也就出在這兒啊,網路上看到的資料中,有已經過時的、有寫錯的,而Google那個萬人迷的Gemini,吃了那些亂七八糟的東西之後,嘴裡吐出來的東西,也是亂七八遭的,根本不知道哪些是正確的,哪些是錯誤的。

既然真相這麼難找,那最後又是怎麼找到的?這個啊,套句電視劇灑狗血用的台詞,就「回歸初心」囉!乖乖的研究pygame的原始檔案中,這部分到底是怎麼設計的。這樣做雖然有點燒腦,但很實在。

在pygame中,混色模式除了BLEND_PREMULTIPLIEDBLEND_ALPHA_SDL2這兩個比較特殊孤僻的模式之外,可以由命名方式區分為兩大類,而其主要的差異在於混色時,包含或不包含透明度。

不包含透明度的混色模式

BLEND_ADD, BLEND_SUB, BLEND_MULT, BLEND_MIN, BLEND_MAX

BLEND_RGB_ADD, BLEND_RGB_SUB, BLEND_RGB_MULT, BLEND_RGB_MIN, BLEND_RGB_MAX

這裡要注意的是,中間有或沒有RGB三個字母,其實是一樣的模式,只是名稱不同而已。例如,BLEND_ADDBLEND_RGB_ADD,指的其實是同樣的模式。

包含透明度的混色模式

BLEND_RGBA_ADD, BLEND_RGBA_SUB, BLEND_RGBA_MULT, BLEND_RGBA_MIN, BLEND_RGBA_MAX

這些模式會利用不同的計算式,來決定混色之後的顏色數值。假設

0 <= src, dest <= 255

當把來源像素的顏色src混色到目標像素的顏色dest而得到顏色c時,各個模式的RGBA值計算式為:

ADD: c = (dest+src) if (dest+src)<=255 else 255

SUB: c = (dest-src) if (dest-src)>=0 else 0

MULT: c = (dest*src+255)//256

MIN: c = min(dest, src)

MAX: c = max(dest, src)

其中MULT模式有兩個比較特別的性質:當destsrc有一個是0時,則混色之後的值,就會是0;而當destsrc有一個是255時,則混色之後的值,會是另外那個顏色的值。所以,當我們把一張具備透明度的圖片,以MULT混色模式blit到一張顏色為(255, 255, 255, A)的圖片之後,所得到的圖片,顏色會跟原來的圖片一樣,而且,完全透明的部分,也會跟原來的圖片一樣;被改變的,就只是完全不透明以及不完全透明部分的透明度。

在pygame的blit()fill()方法中,有個special_flags參數,可以用來選擇混色模式;如果不特別指定而使用預設的混色模式,則混色後的顏色,計算方式為:

if destA == 0:
c = src
A = srcA
else:
    c = (src*srcA + dest*(255-srcA))//255
  A = srcA + destA*(255-srcA)//255

這裡的srcAdestA分別指的是來源像素和目標像素的alpha值,而A則是混色後所得到的alpha值。不過要注意的是,這兩個式子所算出的值,和用pygame所算出的值,可能會有些小小的差距。造成這個小小差距的原因,在於pygame為了加快計算速度,用了很多技巧來避免浮點數運算,但同時也犧牲了一些計算上的準確度。另外,從計算式可以看出來,當目標像素是完全透明時,混色之後得到的會是來源像素,完全無視目標像素的存在。

以上就是pygame各種blend mode的計算方式。這些計算式看起來挺簡單的,不是嗎?但怎會那麼折騰人呢?以下就是挖掘真相的辛酸血淚史。

這一切的一切,都是因為pygame的說明文件,實在是有夠不清不楚的。

在pygame的說明文件中,只列出了各個blend mode的名稱,並沒有說明相關的計算方式。所以,就只能鼻子摸一摸,在網路上搜尋看看有沒有更詳細的資料。

顯然有不少網友有同樣的疑問,所以在stack overflow和reddit上,可以看到不少相關的討論。只是很不幸的,pygame在發展的過程中,針對混色的計算方式,進行過幾次的調整,而網路上查到的那些網友提供的計算式,有一些是調整前的式子,難怪實際測試時,老是得不到預期中的結果。

要想知道pygame各個blend mode所用的計算式,比較好的辦法,就是直接去讀surface.h這個檔案。不過,千萬千萬要注意,網路上有網友提供這個檔案的連結,要讀之前,先確認一下日期,因為那是個過時的檔案,裡頭關於MULT模式的計算式有bug。所以囉,最萬無一失的方法,就是把安裝在自己電腦上的surface.h找出來讀,這樣就不用擔心版本不符的問題了。

在所有的blend mode中,預設模式的計算式花了最多時間才搞清楚。之所以會這樣,還是因為文件寫得不完整。在<Source Alpha to Source Alpha Surface Blit Guarantees — wiki>這篇文章中,說明了pygame在混色時的計算方式。這個其實也就是blend mode預設模式的計算式。只是啊只是,文章中並沒有提到一個特殊狀況:當目標像素是完全透明時,混色之後得到的RGBA值,會和來源像素的RGBA值一模一樣。就因為這個不完整的說明,又讓人昏天暗地的多花了很多時間,才終於搞清楚問題出在哪。

從這個挖掘pygame的blend mode真相的過程就可以知道,清楚且詳細的說明文件,是多麼的重要而且珍貴啊!

留言
avatar-img
ysf的沙龍
20會員
165內容數
寫點東西自娛娛人
ysf的沙龍的其他內容
2025/04/14
花了些時間,靜下心來,仔仔細細地研究了一番,總算把Python呼叫函數時引數的傳遞方式給徹底搞清楚了。
2025/04/14
花了些時間,靜下心來,仔仔細細地研究了一番,總算把Python呼叫函數時引數的傳遞方式給徹底搞清楚了。
2023/12/20
在寫《The Nature of Code閱讀心得筆記——使用Python實作》的[第四章]4.3節時,原書提到,在使用Java的ArrayList時,如果用迴圈一面走訪一面又移除其中的元素,那會有難以察覺的問題存在。寫個小程式測試的結果發現,Python的list也會有一樣的問題。
Thumbnail
2023/12/20
在寫《The Nature of Code閱讀心得筆記——使用Python實作》的[第四章]4.3節時,原書提到,在使用Java的ArrayList時,如果用迴圈一面走訪一面又移除其中的元素,那會有難以察覺的問題存在。寫個小程式測試的結果發現,Python的list也會有一樣的問題。
Thumbnail
2023/10/15
用matplotlib畫正弦函數sin的圖形會有多難呢?應該是挺簡單的。不過,要畫得漂亮讓人滿意,還是非得費一番功夫調整不可。
Thumbnail
2023/10/15
用matplotlib畫正弦函數sin的圖形會有多難呢?應該是挺簡單的。不過,要畫得漂亮讓人滿意,還是非得費一番功夫調整不可。
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
進入選擇敘述語法了。常用的選擇敘述語法,弄懂了就運用自如。
Thumbnail
進入選擇敘述語法了。常用的選擇敘述語法,弄懂了就運用自如。
Thumbnail
不間斷 Python 挑戰 Day 3 - 基本數學運算
Thumbnail
不間斷 Python 挑戰 Day 3 - 基本數學運算
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News