iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 19
1
Modern Web

寫給工程師的 WebGL 學習心得系列 第 19

[WebGL - Day19] PixiJS 濾鏡實作 - glowFilter、PixiJS v4 v5 版濾鏡寫法差異

看懂 alphaFilter 後,來看另一個 filter: glowFilter


glowFilter 與 Photoshop 混和選項的外光暈 / 內光暈 效果相似

光暈濾鏡 - 在物件內或外套上光暈,效果:
討論兩個部分:

  1. 這個濾鏡效果在 PixiJS v4v5 版本上的差異
  2. glowFilter 裡 Fragment Shader 的寫法

PixiJS v4 v5

PixiJS Filter v4 v5
若沒特別調整,v4 與 v5 使用 glowFilter 的結果有點不同

  • PixiJS v4,光暈平均分布在兔子四周
  • PixiJS v5,光暈有被切到

解決這個問題,在濾鏡裡加上 padding 的值即可

// PixiJS v5
const glowFilter = new PIXI.filters.GlowFilter();
glowFilter.padding = 4;

v4 濾鏡的 padding 預設值是 4
v5 濾鏡的 padding 預設值是 0

如果沒有向外延伸濾鏡的範圍,濾鏡效果會被切掉


一些 Built-in uniforms

在 v5 說明文件 裡有提到幾個內建的 uniforms:
PixiJS Filter Built-in Uniforms

內建 uniforms 是 PixiJS v4 與 v5 主要差異之一
不會直接操作到,把值印出來後可以看出一些差別:

僅移動兔子:
PixiJS Filter v5 move
filterArea 前兩個值不變,後兩個則是兔子座標
outputFrame 有變化的兩個值也是兔子座標

僅旋轉兔子:
PixiJS Filter v5 move
原地旋轉時寬高有變化,也影響了 filterArea 的範圍

加了 padding 後,旋轉與移動兔子:
PixiJS Filter v5 padding
加上 padding 後
旋轉與移動時,座標與寬高改變,但濾鏡範圍沒有變
(操作 padding 值時可能會影響 filterArea 的值)


很多時候會聽到 濾鏡很吃效能!這樣的說法
在看得懂 Shader 的寫法後,實際上有機會辨別濾鏡是否真的很吃效能

Glow Filter

Glow Filter src 共有三個檔案:

  • GlowFilter.js
  • glow.frag
  • index.js

主要看的是 GlowFilter.jsglow.frag


GlowFilter.js

幾個部分:

  • PixiJS 內建 rgb2hexhex2rgb 的工具
import {rgb2hex, hex2rgb} from '@pixi/utils';
  • 一些 GlowFilter 的 GetterSetter

  • 正規表示式

import fragment from './glow.frag';
...
super(vertex, fragment
    .replace(/%QUALITY_DIST%/gi, '' + (1 / quality / distance).toFixed(7))
    .replace(/%DIST%/gi, '' + distance.toFixed(7)));

這邊看到一些 fragment.replace() 語法
表示會處理 glow.frag 讀入的字串

glow.frag

幾個部分:

  • PI (圓周率常數)
const float PI = 3.14159265358979323846264;

在 Shader 裡,沒有內建圓周率常數

  • 建構式與預設值、雙重迴圈
constructor(distance = 10, outerStrength = 4, innerStrength = 0, color = 0xffffff, quality = 0.1) {
    ...
})

預設 distance=10quality = 0.1
在 glow.frag 裡取代完之後

%QUALITY_DIST% 是 (1 / quality / distance).toFixed(7),運算完值為"1.0000000"
%DIST% 是 distance.toFixed(7),運算完值為"10.0000000"

將值帶入運算迴圈:

for (float angle = 0.0; angle <= PI * 2.0; angle += %QUALITY_DIST%) {
   cosAngle = cos(angle);
   sinAngle = sin(angle);
   for (float curDistance = 1.0; curDistance <= %DIST%; curDistance++) {
       ...
   }
}

雙迴圈啊,distancs 的大小直接影響到 %QUALITY_DIST%%DIST%
而且是每次運算時皆跑大量迴圈

結論: Glow Filter 確實吃效能,尤其是 光暈效果很大 的時候


本系列主題是學習 WebGL
起步時我推薦從 Shadertoy 的教學開始
較熟悉 Shader 的型別與寫法後
可以看看 PixiJS 裡其他濾鏡的寫法,會很有收穫
並且覺得實際寫 Shader 並沒有那麼可怕了

因為進階的 Shadertoy 範例,或是 Shader of the Week 精選
難度真的很高


上一篇
[WebGL - Day18] PixiJS 濾鏡實作 - alpha filter
下一篇
[WebGL - Day20] 在 three.js 裡寫 Shader
系列文
寫給工程師的 WebGL 學習心得30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

2
愷開
iT邦新手 4 級 ‧ 2019-10-05 19:01:37

WebGL 真的是修羅道,感謝分享!

喔喔,先前看過 WebGL 與 Three.js 初探 系列,WebGL 真的很硬!

我要留言

立即登入留言