[小白进阶]程序化2D纹理-无贴图绘制动态液体效果

使用之前学到的feagment shader的知识综合运用制作无需额外贴图的动态液体效果。

效果可以拆解为四个部分:

  1. 绘制圆形蒙版
  2. 绘制动态液面
  3. 液体与背景的颜色渐变
  4. 绘制动态渐变气泡

【效果展示】

【应用】
可以作为动态图标使用,如魔法瓶中的药水效果。或者作为角色的HP/MP表示等。

【核心思路】

  1. 绘制圆形蒙版
    通过判断当前uv坐标与中心的距离来控制显示。
vec2 maskCenter = vec2(0.5);
float maskDist = distance(v_uv, maskCenter);
col = maskDist < maskRadius ? col : vec4(0.0);

这里需要开启材质的transparent技术,否则圆形外侧是不透明黑色。
image

  1. 绘制动态液面
    需要让液面表现出流动效果,这里使用了正弦函数+时间来模拟,同时暴露了页面高度和页面幅值便于调整效果。
// 绘制动态水面波纹效果
float face_h = sin(v_uv.x * frequency + cc_time.x) * amplitude + (1.0 - height);

计算出水面的y方向高度后便可以作为分界线绘制上下两种颜色。

  1. 液体与背景的颜色渐变
    液体颜色渐变比较简单,可以直接使用mix混合来获得线性渐变的效果。
// 计算颜色梯度获取渐变色
vec4 col = v_uv.y < face_h ? mix(bgColor,bgColor2,1.0 - v_uv.y) : mix(liquidColor,mainColor,v_uv.y);
  1. 绘制动态渐变气泡
    绘制气泡算是效果中比较复杂的部分,首先需要明确的效果是:
    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)相对简单,只需要根据页面高度的大致位置对颜色进行线性混合即可。

【参数】
image
参数解释:
//液体颜色
liquidColor - 底色
mainColor - 插值颜色

//背景颜色
bgColor - 底色
bgColor2 - 插值颜色

//液面控制
frequency - 重复频率
amplitude - 液面幅值
height - 液面高度

//气泡控制
bubbleDensity - 泡泡密度
bubbleRadius - 泡泡大小
bubbleBorder - 泡泡边缘粗细

//蒙版
maskRadius - 蒙版半径

最终完整代码将再整理后上传至应用商店中,目前的实现还比较粗糙,欢迎大家一起讨论。

3赞