godot-plateformer/_shader/ripple2.gdshader

150 lines
4.9 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

shader_type canvas_item;
// ✅ Godot 4必须这样拿屏幕纹理不能用 SCREEN_TEXTURE
uniform sampler2D screen_tex : hint_screen_texture, filter_linear_mipmap;
// 可视化调试R=通道G=边缘脊B=尾迹
uniform bool debug_show = false;
// 由脚本每帧传入屏幕UV 0~1
uniform vec2 obj_uv = vec2(0.5, 0.5);
uniform vec2 obj_dir = vec2(1.0, 0.0);
uniform float obj_speed = 1.0;
// 可选噪声:建议给一张灰度噪声(Perlin/BlueNoise)
// 没有也能跑,只是边缘会更规整
uniform sampler2D noise_tex : filter_linear, repeat_enable;
// -------- 形状(开槽+水脊)--------
uniform float lane_half_width = 0.085; // 通道半宽(越大拨开越宽)
uniform float edge_width = 0.040; // 水脊宽度(卷起那条边)
uniform float trail_length = 0.55; // 尾迹长度
// -------- 位移强度(核心)--------
uniform float push_strength = 0.075; // 两侧推开(主要折射)
uniform float drag_strength = 0.045; // 沿方向拖拽(带走水)
uniform float suck_strength = 0.030; // 中心下陷(通道更像被挖开)
uniform float curl_strength = 0.070; // 卷边强度(更像拨水卷起)
// -------- 泡沫/细节 --------
uniform float foam_strength = 0.45; // 水脊亮边强度
uniform float noise_scale = 3.5; // 噪声缩放
uniform float noise_advect = 0.50; // 噪声随时间沿方向流动速度
uniform float chroma_shift = 0.60; // 色散强度0=无)
float sat(float x) { return clamp(x, 0.0, 1.0); }
vec2 safe_norm(vec2 v) {
float l = length(v);
return (l > 1e-5) ? (v / l) : vec2(1.0, 0.0);
}
float n2(vec2 uv) {
// 如果你没设置 noise_tex这里通常会是 0效果依旧能跑
return texture(noise_tex, uv).r;
}
// 用噪声梯度构造“卷动方向”(让边缘像被拨起来)
vec2 curl_dir(vec2 uv) {
float e = 0.002;
float nL = n2(uv - vec2(e, 0.0));
float nR = n2(uv + vec2(e, 0.0));
float nD = n2(uv - vec2(0.0, e));
float nU = n2(uv + vec2(0.0, e));
vec2 g = vec2(nR - nL, nU - nD);
return safe_norm(vec2(-g.y, g.x));
}
void fragment() {
vec2 uv = SCREEN_UV;
vec2 dir = safe_norm(obj_dir);
vec2 perp = vec2(-dir.y, dir.x);
// 局部坐标(相对玩家)
vec2 v = uv - obj_uv;
float forward = dot(v, dir); // 沿前进方向(身后为正)
float side = dot(v, perp); // 左右偏移
// 只在“身后”生效(像船头拨水/尾迹)
float behind = step(0.0, forward);
// 更像粘稠的尾迹衰减(指数衰减)
float trail = exp(-forward / max(trail_length, 1e-4)) * behind;
// 通道(中间被拨开的区域)
float lane = 1.0 - smoothstep(lane_half_width, lane_half_width * 1.35, abs(side));
// 水脊(在通道边缘一圈)
float edge = 1.0 - smoothstep(edge_width, 0.0, abs(abs(side) - lane_half_width));
// 噪声坐标:沿运动方向流动
vec2 flow_uv = uv * noise_scale + dir * (TIME * noise_advect);
float nn = n2(flow_uv);
float wobble = (nn * 2.0 - 1.0);
// 速度缩放(慢就弱)
float spd = sat(obj_speed);
// 推开方向(左右分开)
float sgn = sign(side + 1e-6);
vec2 push = perp * sgn;
// “抽走”方向(让中间更凹/更干净)
vec2 suck = -push;
// 卷边:用 curl_dir + push 混合,让边缘有翻卷感
vec2 cdir = curl_dir(flow_uv);
vec2 curl = (cdir + push * 0.6) * (edge * trail);
// 组装位移场(折射偏移)
vec2 offset = vec2(0.0);
// 1) 中央通道推开
offset += push * (lane * trail) * (push_strength * spd);
// 2) 沿方向拖拽(把水带走)
offset += dir * (lane * trail) * (drag_strength * spd);
// 3) 中心下陷/抽走(更像被拨开挖出槽)
offset += suck * (lane * trail) * (suck_strength * spd);
// 4) 边缘卷动(水脊翻起)
offset += curl * (curl_strength * spd);
// 5) 边缘破碎(泡沫感)
offset += push * wobble * (edge * trail) * (0.02 * spd);
// 先准备输出颜色变量(避免 return
vec3 col;
if (debug_show) {
// debugR=通道G=边缘B=尾迹
col = vec3(lane, edge, trail);
} else {
// ===== 折射采样(带一点色散)=====
vec2 o = offset;
if (chroma_shift > 0.001) {
float cs = chroma_shift * 0.002; // 色散很容易过头,保持小
float r = texture(screen_tex, uv + o * (1.0 + cs)).r;
float g = texture(screen_tex, uv + o).g;
float b = texture(screen_tex, uv + o * (1.0 - cs)).b;
col = vec3(r, g, b);
} else {
col = texture(screen_tex, uv + o).rgb;
}
// ===== 泡沫亮边 =====
float foam = edge * trail * spd;
foam *= (0.55 + 0.45 * wobble); // 破碎感
foam = sat(foam);
col += foam * foam_strength;
}
COLOR = vec4(col, 1.0);
}