使用之前学到的feagment shader的知识综合运用制作无需额外贴图的动态液体效果。
效果可以拆解为四个部分:
- 绘制圆形蒙版
- 绘制动态液面
- 液体与背景的颜色渐变
- 绘制动态渐变气泡
【效果展示】
【应用】
可以作为动态图标使用,如魔法瓶中的药水效果。或者作为角色的HP/MP表示等。
【核心思路】
- 绘制圆形蒙版
通过判断当前uv坐标与中心的距离来控制显示。
vec2 maskCenter = vec2(0.5);
float maskDist = distance(v_uv, maskCenter);
col = maskDist < maskRadius ? col : vec4(0.0);
这里需要开启材质的transparent技术,否则圆形外侧是不透明黑色。

- 绘制动态液面
需要让液面表现出流动效果,这里使用了正弦函数+时间来模拟,同时暴露了页面高度和页面幅值便于调整效果。
// 绘制动态水面波纹效果
float face_h = sin(v_uv.x * frequency + cc_time.x) * amplitude + (1.0 - height);
计算出水面的y方向高度后便可以作为分界线绘制上下两种颜色。
- 液体与背景的颜色渐变
液体颜色渐变比较简单,可以直接使用mix混合来获得线性渐变的效果。
// 计算颜色梯度获取渐变色
vec4 col = v_uv.y < face_h ? mix(bgColor,bgColor2,1.0 - v_uv.y) : mix(liquidColor,mainColor,v_uv.y);
- 绘制动态渐变气泡
绘制气泡算是效果中比较复杂的部分,首先需要明确的效果是:
a). 泡泡的轮廓是一个环形,即中心是透明的
b). 泡泡自底向上运动
c). 不同泡泡的位置和速度要稍微不同,否则看起来不自然
d). 泡泡到达液面附近颜色过渡并自然消失
对于a需求,我们还是根据uv坐标确定泡泡中心的距离,绘制泡泡的白色边缘轮廓,暴露轮廓的宽度和泡泡半径用于调节。
float dist = distance(uv, center);
col = dist < radius - border || dist > radius + border ? col : bubbleCol;
对于b)和c)需求,可以利用坐标取整+正弦函数的特性结合时间来控制泡泡中心的位置,并分片确定泡泡绘制区域,这样避免遍历较远的泡泡,减少不必要的开销。
float pos_y = mod(1.0 - mod(cc_time.x * 0.1, 1.0 + sin(roundInt(v_uv.x,1.0) * 12.6794) * 0.5 + 0.5), height);
vec2 bubbleCenter = vec2(roundInt(v_uv.x,1.0), pos_y + sin(roundInt(v_uv.x,1.0) * 12.6794) * 0.5 + 0.5);
最后d)相对简单,只需要根据页面高度的大致位置对颜色进行线性混合即可。
【参数】

参数解释:
//液体颜色
liquidColor - 底色
mainColor - 插值颜色
//背景颜色
bgColor - 底色
bgColor2 - 插值颜色
//液面控制
frequency - 重复频率
amplitude - 液面幅值
height - 液面高度
//气泡控制
bubbleDensity - 泡泡密度
bubbleRadius - 泡泡大小
bubbleBorder - 泡泡边缘粗细
//蒙版
maskRadius - 蒙版半径
最终完整代码将再整理后上传至应用商店中,目前的实现还比较粗糙,欢迎大家一起讨论。
