Glow Effect using Godot Understanding the Blur Glow Demo in GDQuest Shader Secret

這篇的圖片和範例出處是 GDQuest shader secret 的 BlurGlowDemo

目標是用 shader language 在下面的圖片背後加上神秘的光芒

View post on imgur.com

Step 1

首先用下面的 shader 做個剪影

shader_type canvas_item;
uniform vec4 glow_color : hint_color = vec4(1.0);

void fragment() {
  vec4 color = texture(TEXTURE, UV);
  COLOR = vec4(glow_color.rgb, color.a);
}

就把每個 UV 顏色
換成預計要的發光色 glow_color

View post on imgur.com

Step 2

再來用高斯亂數雜訊
對 X 軸做模糊化
(ex: blur_scale = (4,0))

shader_type canvas_item;
const float SAMPLES = 71.0;
const float PI2 = 6.283185307179586476925286766559;

uniform vec2 blur_scale = vec2(1, 0);

float gaussian(float x) {
  float x_squared = x*x;
  float width = 1.0 / sqrt(PI2 * SAMPLES);
  return width * exp((x_squared / (2.0 * SAMPLES)) * -1.0);
}

void fragment() {
  vec2 scale = TEXTURE_PIXEL_SIZE * blur_scale;
  float weight = 0.0;
  float total_weight = 0.0;
  vec4 color = vec4(0.0);

  for(int i=-int(SAMPLES)/2; i < int(SAMPLES)/2; ++i) {
    weight = gaussian(float(i));
    color += texture(TEXTURE, UV + scale * vec2(float(i))) * weight;
    total_weight += weight;
  }

  COLOR = color / total_weight;
}

 

Step 3

然後模糊化的圖形基礎上
用同樣的方法對 Y 軸做模糊化
(ex: blur_scale = (0,4))

View post on imgur.com

需注意的地方是,
這要分二個步驟做,
一次同時模糊化 X/Y
結果是如下的類 shear matrix 的效果
(ex: blur_scale = (4,4))
這不是我們要的

View post on imgur.com

Step 4

最後,
用下面的 shader 把
1. 一開始的剪影 (prepass_texture)
2. 模糊化的影像 (blur_texture)
3. 機器人的原圖 (TEXTURE)
三個合體,產生最後的圖

shader_type canvas_item;
uniform sampler2D prepass_texture;
uniform sampler2D blur_texture;
uniform float glow_intensity;

void fragment() {
  vec4 color = texture(TEXTURE, UV);
  vec4 prepass = texture(prepass_texture, UV);
  vec4 blurred = texture(blur_texture, UV);
  vec3 glow = max(vec3(0.0), blurred.rgb-prepass.rgb);

  vec3 out_color = color.rgb + glow.rgb * glow_intensity;

  COLOR = vec4(out_color, clamp(out_color.r + out_color.g + out_color.b, 0, 1));
}

View post on imgur.com

然後把機器人放上去

View post on imgur.com

完成了
更改剪影顏色可以改光的顏色
更改最後的 glow_intensity 或模糊化的 blur_scale
可以更改光暈或亮度

然後是 Godot 實作相關

當 shader 裡要取得前幾個步驟的圖片的像素,
需要用 ViewPort Texture。

所以範例裏做剪影用了一個 viewport,
模糊化X/Y各用一個 viewport,
最後合體也用了一個 viewport,
然後因為 shader 或 Godot 需要,
每個 ViewPortContainer 要改 size
然後 viewport 要改
1. size
2. transparent_bg = true
3. Usage = 2D
4. Update Mode = Always

然後 viewport 需要用 ViewPortContainer (VPC) 包起來
因此檔案架構像是這樣

+Blur_Y (VPC, 模糊圖)
+ viewport
+ Blur_X (VPC)
+ viewport
+ Prepass (VPC)
+ Sprite (機器人圖)

+MainView (VPC, 合體)
+ viewport
+ Sprite (機器人圖)

範例看起來很複雜,
不過做的事就上面寫的那些
=================

如果到 Youtube 上找 Godot 2D Glow Effect,
會找到好幾個用
WorldEnvironment -> Glow 來做發光的範例,
viewport 裡面可以加獨立的 Environment
用裡面的 Glow 效果做出來的長相是

View post on imgur.com

你可以看出來
雖然都叫 Glow
但這是完全不同的效果

如果想要類似的效果
我預想是可以先用 shader 做剪影
再對剪影套用 WorldEnvironment Glow,
再蓋上原圖的作法
不過這部分是我猜想的
實驗部份我就不做了