MatchMaster/assets/resources/shader/rainbow_bottle.effect
2026-09-15 20:14:07 +08:00

108 lines
3.1 KiB
Plaintext

CCEffect %{
techniques:
- passes:
- vert: rainbow-water-vs
frag: rainbow-water-fs
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
rasterizerState:
cullMode: none
depthStencilState:
depthTest: false
depthWrite: false
properties:
texture: { value: white }
uvRect: { value: [0, 0, 1, 1] }
uvRotated: { value: 0 }
water: { value: [1, 0, 0.024, 0.006] }
}%
CCProgram rainbow-water-vs %{
precision highp float;
#include <cc-global>
#include <cc-local>
in vec3 a_position;
in vec4 a_color;
in vec2 a_uv0;
out vec4 v_color;
out vec2 v_uv0;
void main () {
vec4 pos = vec4(a_position, 1.0);
#if CC_USE_MODEL
pos = cc_matViewProj * cc_matWorld * pos;
#else
pos = cc_matViewProj * pos;
#endif
gl_Position = pos;
v_color = a_color;
v_uv0 = a_uv0;
}
}%
CCProgram rainbow-water-fs %{
#if CC_SUPPORT_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
precision highp float;
#include <texture>
in vec4 v_color;
in vec2 v_uv0;
uniform sampler2D texture;
uniform WaterProperties {
vec4 uvRect;
vec4 water;
float uvRotated;
};
void main () {
vec2 uv = (v_uv0 - uvRect.xy) / max(uvRect.zw, vec2(0.00001));
if (uvRotated > 0.5) uv = vec2(uv.y, 1.0 - uv.x);
vec4 base = vec4(1.0);
{
CCTexture(texture, v_uv0, base);
}
// 固定波形从左向右平移,瓶内颜色跟随同一波列,不在中途叠出新的凸起。
float phase = uv.x * 7.5 - water.y * 1.8;
float envelope = 4.0 * uv.y * (1.0 - uv.y);
vec2 drift = vec2(0.0, 0.75 * sin(phase + uv.y * 3.0));
vec2 flowingUV = clamp(uv + drift * water.z * envelope, vec2(0.001), vec2(0.999));
if (uvRotated > 0.5) flowingUV = vec2(1.0 - flowingUV.y, flowingUV.x);
vec4 flowing = vec4(1.0);
{
CCTexture(texture, uvRect.xy + flowingUV * uvRect.zw, flowing);
}
vec4 color = vec4(mix(base.rgb, flowing.rgb, flowing.a), base.a);
// 液面沿同一方向连续推进;空瓶不残留,满瓶保持完整。
float amplitude = water.z * smoothstep(0.0, 0.08, water.x)
* smoothstep(0.0, 0.08, 1.0 - water.x);
float wave = amplitude * sin(phase);
float surface = water.x + wave;
float height = 1.0 - uv.y;
float distanceToSurface = height - surface;
float feather = water.w;
#if CC_SUPPORT_standard_derivatives
// 按实际屏幕像素抗锯齿,缩小瓶子后液面仍能平滑跨过像素边界。
feather = max(0.75 * fwidth(distanceToSurface), 0.00001);
#endif
if (water.x <= 0.0) {
color.a = 0.0;
} else if (water.x < 1.0) {
color.a *= 1.0 - smoothstep(-feather, feather, distanceToSurface);
float rim = 1.0 - smoothstep(0.0, feather, abs(distanceToSurface));
color.rgb = mix(color.rgb, vec3(1.0, 0.98, 0.88), rim * 0.08);
}
color *= v_color;
#if USE_BGRA
gl_FragColor = color.bgra;
#else
gl_FragColor = color;
#endif
}
}%