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 #include 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 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 } }%