用 Shader 写个完美的波浪~
前言
皮皮最近接到了一个小需求:
👧美术小姐姐:皮皮皮皮,你会不会做奶茶?
😱我:???
👧美术小姐姐:就是那种,奶茶的轮廓加上动态水波纹~
🙄我:吓死我还以为让我做喝的奶茶...
👧美术小姐姐:炒鸡多图片都需要这种效果,用动画的话工作量太大了!
🤓我:波浪效果是吧,小意思,一个月的奶茶就够了,或者扫码提需求~
👧美术小姐姐:皮?🔨🔨🔨
🤪我:卒~
俗话说:遇事不决,量子力学写虽得儿。
根据我多年喝奶茶的经验,像这种效果用 Shader 做就再简单不过了,最终的效果如下:
趁此机会,本篇文章就来与小伙伴们分享动态波浪 Shader 的原理和制作思路吧。
要注意的是,这是一篇偏入门的文章,写得会相对比较详细,尽量让不懂 Shader 的小白也可以看懂,这也是我写文章的一贯风格。
好了,话不多说,进入正题~
正文
🧐整体思路
看到波浪的表现特点我第一时间想到的就是正弦曲线(或者说是正弦波,又让我想起了示波器)。
🔢正弦曲线(Sinusoid)
「正弦曲线」是三角函数中的一种正弦(Sine)比例的曲线。正弦曲线表现为一条波浪线,形状犹如海上完美的波浪。
标准的正弦函数公式为:
正弦函数属于周期函数,其值域为 [-1, 1]
。
如下图就是一个纯正标准的正弦曲线:
而一般我们常用的正弦曲线公式为:
这条公式比标准公式多了几个常数,含义如下:
-
A
: 「振幅(Amplitude)」,曲线最高点与最低点的差值,表现为曲线的整体高度 -
ω
: 「角速度(Angular Velocity)」,控制曲线的周期,表现为曲线的紧密程度 -
φ
: 「初相(Initial Phase)」,即当x = 0
时的相位,表现为曲线在坐标系上的水平位置 -
k
: 「偏距(Offset)」,表现为曲线在坐标系上的垂直位置
相位(Phase):上方公式中的
ωx±φ
部分称为相位,相位发生在周期性的运动之中,最直接的理解就是角度。
☕稍加思索
有了公式之后,我们可以尝试调整其中的常数来改变函数曲线的形态。
在查看下方的示例时,请尝试将「曲线形态的变化」与「右上角公式的变化」关联起来。
改变曲线的高度
我们可以调整常数 A
(振幅)来改变曲线的值域(值域为 [-A, A]
):
改变曲线的周期
我们可以调整常数 ω
(角速度)来改变曲线的周期:
改变曲线的水平位置
我们可以调整常数 φ
(初相)来改变曲线的水平位置:
多说一句
其实对于“曲线的水平位置”这个描述是不太准确的,因为初相实际上改变的是当 x = 0
时的相位,也就直接影响函数曲线在 x = 0
处的位置。
所以说曲线的位置并没有真正改变,而只是曲线的形态发生了改变。
但是由于正弦曲线的周期性特点,曲线的这种形态变化看起来像是曲线进行了位移。
改变曲线的垂直位置
我们可以调整常数 k
(偏距)来改变曲线的垂直位置:
🤠动手实现
明白了正弦曲线的特性之后,接下来我们需要做的就是在代码中运用正弦函数。
慢着!正弦曲线确实如海上完美的波浪般优美,但是正弦曲线是静态的,我们要的波浪是动态的啊!
🌊如何让曲线动起来
别慌!还记得我们可以调整「初相」来改变曲线的“水平位置”吗?
既然如此,我们可以给初相加入「时间因素」,使得 y 值可以随着时间的增加发生「周期性变化」,看起来就像是曲线在进行“水平位移”。
就像这样:
得到新的公式
加入时间因素 t
后的曲线公式:
🧩On Shadertoy
小贴士:由于 GLSL ES 没有办法进行调试,所以写 Shader 时可以先在 Shadertoy 中编写并在线预览,显著提高效率。
「一切尽在注释中,简单详细且直观。」
主函数代码如下:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// 将像素坐标归一化(区间 [0.0, 1.0])
// iResolution 是 Shadertoy 提供的视口分辨率全局变量(类型:vec3)
vec2 uv = fragCoord / iResolution.xy;
// 振幅(控制波浪顶端和底端的高度)
float amplitude = 0.05;
// 角速度(控制波浪的周期)
float angularVelocity = 10.0;
// 频率(控制波浪移动的速度)
float frequency = 10.0;
// 偏距(设为 0.5 使得波浪垂直居中于屏幕)
float offset = 0.5;
// 初相位(正值表现为向左移动,负值则表现为向右移动)
// iTime 是 Shadertoy 提供的运行时间全局变量(类型:float)
float initialPhase = frequency * iTime;
// 代入正弦曲线公式计算 y 值
// y = Asin(ωx ± φt) + k
float y = amplitude * sin((angularVelocity * uv.x) + initialPhase) + offset;
// 区分 y 值上下部分,设置不同颜色
vec4 color = uv.y > y ? vec4(0.0, 0.0, 0.0, 1.0) : vec4(0.0, 0.7, 0.9, 1.0);
// 输出到屏幕
fragColor = color;
}
预览效果如下(🌊是不是有内味儿了):
在线预览:https://www.shadertoy.com/view/ttSfRh
🥥On Cocos Creator
我们主要关注片段着色器部分,这里就不展示整个 Effect 文件的代码了,直接上传送门吧。
Effect 文件:https://gitee.com/ifaswind/eazax-ccc/blob/master/resources/effects/eazax-sine-wave.effect
代码核心其实就是套用了公式,我们代码注释一起看吧。
「一切尽在注释中,简单详细且直观。」
片段着色器代码如下:
CCProgram fs %{
precision highp float;
// 引入 Cocos Creator 内置的全部变量
#include <cc-global>
// 顶点颜色(来自顶点着色器)
in vec4 v_color;
// UV 坐标(来自顶点着色器)
in vec2 v_uv0;
// 纹理
uniform sampler2D texture;
// 自定义属性
uniform Properties {
float amplitude; // 振幅
float angularVelocity; // 角速度
float frequency; // 频率
float offset; // 偏距
};
void main () {
// 保存顶点颜色
vec4 color = v_color;
// 叠加纹理颜色
color *= texture(texture, v_uv0);
// 直接丢弃原本就透明的像素
if (color.a == 0.0) discard;
// 初相位(正值表现为向左移动,负值则表现为向右移动)
// cc.time 是 Cocos Creator 提供的运行时间全局变量(类型:vec4)
float initiaPhase = frequency * cc_time.x;
// 代入正弦曲线公式计算 y 值
// y = Asin(ωx ± φt) + k
float y = amplitude * sin(angularVelocity * v_uv0.x + initiaPhase) + offset;
// 丢弃 y 值以上的像素(左上角为原点 [0.0, 0.0])
if (v_uv0.y < y) discard;
// 输出颜色
gl_FragColor = color;
}
}%
运行效果如下:
使用 cc.tween
动态改变高度(偏距)实现波浪进度条:
cc.tween(this.sineWave)
.to(3, { height: 1 })
.to(0.5, { amplitude: 0 })
.start();
在线预览:https://ifaswind.gitee.io/eazax-cases?case=sineWave
SineWave 组件:https://gitee.com/ifaswind/eazax-ccc/blob/master/components/effects/SineWave.ts
专题
《一起学 Shader》这个专题断更了一段时间,很对不起小伙伴们,是时候续上了😹
更多分享
公众号
😺菜鸟小栈
💻我是陈皮皮,这是我的个人公众号,专注但不仅限于游戏开发、前端和后端技术记录与分享。
💖每一篇原创都非常用心,你的关注就是我原创的动力!
Input and output.
本文分享自微信公众号 - 菜鸟小栈(iamchenpipi)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
华为操作系统 29 年史
2019年8月,华为 HDC 2019 大会发布鸿蒙系统(HarmonyOS)1.0之后,有了解华为的人写了一篇文章《华为操作系统28年史》。今天再来看,就变成了29年史。 通常提到鸿蒙 OS 及其历史,方舟编译器和2012年发布的 LiteOS 被认为是其早期雏形,已经有接近10年的历史。但是这篇文章从上世纪90年代初开始讲起,回顾华为最早有关操作系统的故事。在2020年 HDC 大会到来之前,再看这篇文章,或许可以帮助了解操作系统研发应用之不易,也更能理解操作系统研发现状。 作者:老兵戴辉 转载自:公众号 最牛博弈 侵删 链接:https://mp.weixin.qq.com/s/pdoFVlUM2kXHvGgXo65K-w 8月9日,东莞松山湖沸腾的一天,华为消费者业务CEO余承东发布了鸿蒙操作系统,中文来自山海经,英文叫HarmonyOS,不是以前传说的OakOS。 余承东在介绍鸿蒙OS开发初衷时表示:“随着全场景智慧时代的到来,华为认为需要进一步提升操作系统的跨平台能力,包括支持全场景、跨多设备和平台的能力以及应对低时延、高安全性挑战的能力,因此逐渐形成了鸿蒙OS的雏形。鸿蒙...
- 下一篇
实战解读,超多人实时音视频互动方案的探索与实现
技术的日新月异,推动了产业的不断升级。 随着远程办公、在线教育、直播带货等深入人心,跨时间、地域的大规模音视频远程会议,在线教育由1对1小班向多人互动小班升级,直播带货从单房间百万级别观看人数上升为千万级别,无不对超多人实时音视频技术提出巨大挑战。 为改变这一现状,并满足大规模远程会议、在线教育等应用场景,9月17日,即构科技解决方案资深专家许明龙将为大家带来《超多人实时音视频互动方案探索与实现》技术分享,基于全球领先的语音视频解决方案,灵活支持互动小班和大规模会议,跨国一样低延迟! 即构科技解决方案资深专家许明龙 许明龙,即构科技解决方案资深专家,擅长音视频在Electron、Flutter等平台的技术实践,致力于探索音视频在各个领域的方案验证和实现,曾主导TalkLine视频会议平台和好未来、掌门一对一、作业帮等多个头部教培机构在线教育平台的建设工作。 许明龙将重点从三个层面阐述,如何应对超多人实时音视频互动方案与实现: 在服务器架构设计层面,如何全球化支持单房间百万级别用户并发、千万级别并发推拉流; 在客户端层面,如何快速接入服务器,信令和流媒体如何协调,保障在大规模视频互动场景...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8编译安装MySQL8.0.19
- CentOS关闭SELinux安全模块
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器