这篇的图片和范例出处是
GDQuest shader secret 的 BlurGlowDemo 连结
https://github.com/GDQuest/godot-shaders
算是读书报告吧?
目标是用 shader language
在下面的图片背后加上神秘的光芒
https://i.imgur.com/5RC7n1X.png
[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
https://i.imgur.com/YG1EwuM.png
[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;
}
https://i.imgur.com/HixMdyz.png
[Step 3]
然后模糊化的图形基础上
用同样的方法对 Y 轴做模糊化
(ex: blur_scale = (0,4))
https://i.imgur.com/66R0DyM.png
需注意的地方是,
这要分二个步骤做,
一次同时模糊化 X/Y
结果是如下的类 shear matrix 的效果
(ex: blur_scale = (4,4))
这不是我们要的
https://i.imgur.com/tMR3shc.png
[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));
}
https://i.imgur.com/9TQmsVq.png
如果拿掉上面的机器人图长这样
https://i.imgur.com/39nwpiQ.png
完成了
更改剪影颜色可以改光的颜色
更改最后的 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 效果做出来的长相是
https://i.imgur.com/q9He3K3.png
你可以看出来
虽然都叫 Glow
但这是完全不同的效果
如果想要类似的效果
我预想是可以先用 shader 做剪影
再对剪影套用 WorldEnvironment Glow,
再盖上原图的作法
不过这部分是我猜想的
实验部份我就不做了