用shader做一个柿子颜色的过场动画
想要提高编写shader的水平,需要不断学习和练习。
跪着看完大神们的shadertoy作品后打算自己找个软柿子捏一捏。想了半天打算实现一下Nintendo Switch主机进eShop时的过场动画,仔细一看个过场的颜色和柿子还有点像,。本文将各个技术点整理分享给大家。
先来看一下原效果:
(eShop禁用主机录屏,视频为手机录制)
效果概括(可跳过)
原效果中有四种颜色轮流出现,并且互相覆盖,在视觉上有一种层次感。
在第一层播放过程中,第二层就已经出现,最多同时出现三种颜色。
四种颜色轮播完毕后动画暂停一小段时间,接着重新播放。第四种颜色和一开始的背景色相同,所以动画首尾连接。
入场的形状是阶梯造型,并且阶梯的距离在屏幕两边时比较窄,运行到屏幕中间时最大。
实现方案
运动轨迹
从原效果上看,运动时有缓入和缓出。
先简化处理,只控制某个颜色出场时第一个像素的 x
位置,选择 -cos(t)
作为运动的速度曲线。
对应地,将屏幕的x范围映射到(-1, 1)区间,x = 0的位置在屏幕中下方。
const float PI = 3.14159;
const float TOTAL_TIME = PI * 4.; // 一遍动画的总时间
const vec3 C0 = vec3(1., 0.4667, 0.); // 背景色
const vec3 C1 = vec3(1., 0.5882, 0.0784); // 第一个颜色void mainImage(out vec4 fragColor, in vec2 fragCoord)
{vec2 uv = fragCoord / iResolution.xy;uv.x = uv.x * 2.0 - 1.0; // x居中,范围为(-1, 1)float t = mod(iTime * 2.5, TOTAL_TIME); // 全局时间2.5倍速度播放。对全局时间取模,保证t总是在(0, TOTAL_TIME)范围,实现时间循环float mask = 1.0 - step(-cos(t), uv.x); // -cos(t)像是一个“游标”,左侧为C1,右侧为C0vec3 col = mix(C0, C1, mask); // 根据mask选择颜色fragColor = vec4(col, 1.0); // 输出颜色return;
}
时间分片
控制某个颜色的动画是否显示的逻辑,采用“遮罩”的方式。原理和上一篇的“带通”类似。只不过这里的“遮罩”不是处理空间,而是处理时间。
可以理解为四个颜色的动画无时无刻都在自己运行,当时间处于某个区间内时,对应的颜色才会被画出来。
按顺序分配各颜色的出场时间,第一种颜色出场时间是0,第二种颜色是T1 = PI,第三种是T2 = 2PI,以此类推,第四种颜色播放完毕后是4PI。
实际运行时间不是4PI也没有关系,对全局时间 iTime
进行缩放可以很方便控制整体动画的节奏,所以4PI更像是一个逻辑时间单位。
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{vec2 uv = fragCoord / iResolution.xy;uv.x = uv.x * 2.0 - 1.0;vec3 col = C0;float t = mod(iTime * 2.5, TOTAL_TIME);float mask = 1.0;float cursor = step(-cos(t), uv.x);mask = 1.0 - cursor;col = mix(col, C1, mask);mask = cursor * step(T1, t); // T1之后才显示第2种颜色,时间t < T1时受step()函数影响mask = 0col = mix(col, C2, mask); // 根据mask选择颜色,mask = 0时选择老的颜色mask = (1.0 - cursor) * step(T2, t); // T2之后才显示第3种颜色col = mix(col, C3, mask);mask = cursor * step(T3, t); // T3之后才显示第4种颜色col = mix(col, C4, mask);fragColor = vec4(col, 1.0);
}
阶梯造型
阶梯造型的规律性很强,可以看出是对y坐标做离散化拆成“行”,然后对各“行”进行一定的偏移。
// 对y离散化
float offsety = floor(uv.y * GRID_COUNT) / GRID_COUNT;// 时间t进行offsety偏移,为了避免在t = 0时出现负数导致三角函数“反弹”,做了clamp处理
mask = 1.0 - step(-cos(clamp(t - offsety, 0., TOTAL_TIME)), uv.x);
col = mix(col, C1, mask);
处理颜色交叉
本文一开始提到会有同屏出现三种颜色的情况。仔细观察效果可以发现在第一种颜色到达末端前第二种颜色已经出场了。要处理这种情况只需要对t进行偏移使下一个动画提前播放即可。
float offsety = floor(uv.y * GRID_COUNT) / GRID_COUNT;
mask = 1.0 - step(-cos(clamp(t - offsety, 0., TOTAL_TIME)), uv.x);
col = mix(col, C1, mask);t += h; // 对t进行偏移,h是下一个动画出场的时间提前量mask = step(-cos(clamp(t - offsety, T1, TOTAL_TIME)), uv.x) * step(T1, t);
col = mix(col, C2, mask);
末尾动画停留
本来规划的4PI时间,但是由于上面将每个颜色的播放提前了,导致4PI长度的时间末尾会有一段空白时间,这段时间就刚好用来模拟原效果里的停留效果。想要调整停留时间可以修改 TOTAL_TIME
。
最后调整一下屏宽和动画速度,完工!
总结
老实说这柿子有点硬,我肝了一整天。
每个基本功能单独实现都很简单,但是合并到一起后经常出现牵一发动全身的情况。
写完shader再从头到尾看一遍,可以发现一些可以简化或者合并的部分。一开始我是采用 sin()
作为运动曲线,也尝试过映射到不同的屏幕坐标范围,后来都调整了。
目前的代码没有经过深度调优,尽量保持了和自己的思路比较匹配的写法。
完整代码可从下方领取。
Demo地址
shadertoy
https://www.shadertoy.com/view/ttfBDf
Cocos Creator
https://github.com/caogtaa/CCBatchingTricks
内含各种Cocos Creator编程技巧Demo
本文Demo可直接访问场景文件 SceneEnterEShop
技术交流,欢迎加我微信:ezglumes ,拉你入技术交流群。
推荐阅读:
音视频面试基础题
OpenGL ES 学习资源分享
一文读懂 YUV 的采样与格式
OpenGL 之 GPUImage 源码分析
推荐几个堪称教科书级别的 Android 音视频入门项目
觉得不错,点个在看呗~
用shader做一个柿子颜色的过场动画相关推荐
- unity笔记,如何做一个帅气的大招过场动画。
unity可以通过 v i d e o p l a y e r videoplayer videoplayer组件在各个平面添加动画,但单单播放视频在横版闯关游戏中是很少见的,我们可能更想要一个帅气的 ...
- imwrite函数 matlab_用matlab做一个脉动磁势分解的动画
:::::在知乎上看到别人用matlab做动画就想学学,正好电机学讲到绕组磁势,那就做一个脉动磁势分解成两个旋转磁势来练练手,同时保存为了avi和gif clear all; outputVideo ...
- matlab动画_用matlab做一个脉动磁势分解的动画
:::::在知乎上看到别人用matlab做动画就想学学,正好电机学讲到绕组磁势,那就做一个脉动磁势分解成两个旋转磁势来练练手,同时保存为了avi和gif clear all; outputVideo ...
- Unity Shader 做一个简单的波浪 屏幕扭曲
v2f vert (appdata v) {v2f o;v.vertex.y = v.vertex.y + sin(v.vertex.x + _Time.y) ;o.vertex = UnityObj ...
- 设计-来做一个Windows hello的小动画
今天想和大家分享的是一个Windows hello的动画,也就是这个笑脸的效果. 当时是因为一个小伙伴在交流群里问了一下这个效果是怎么制作的,我觉得还挺有意思的,就觉得复刻一下,顺便出一期教程来讲讲其 ...
- scratch(图形化编程工具)使用漩涡和马赛克特效做一个酷酷的背景动画
我们先看一下效果: 动图效果.如果用视频转gif的话,因为有马赛克就很容易糊掉,所以我放到视频号上,大家想看的可以点击下边视频号看一下效果. 背景部分的代码: 文字部分地面如下: 好了,今天的教程就分 ...
- WPF背景颜色变化的动画
//想做一个背景颜色变化的动画,开始想用透明因子Opacity来实现,后来发现可以改变渐变线性刷LinearGradienBrush的Offset来实现 //就是在设置Storyboard.Targe ...
- 如何制作一个有颜色的ListBox,颜色选择下拉列表
经常我们会遇到要做一个选择颜色的ListBox的情况,下面通过使用一个html控件,如 <Select><\Select> 标签来实现ListBox功能,往往比使用 <a ...
- 用js做一个鼠标惯性动画
用js做一个简单的鼠标惯性动画 <style type="text/css">#div1{width: 50px;height: 50px;background: re ...
最新文章
- 由浅入深剖析.htaccess
- java练习:打印 数字1、2、3、4的组合,不能以4开头,1和3不能相邻,且数字不能重复
- 使用Atomikos Transactions Essentials实现多数据源JTA分布式事务--转载
- R 学习 - 功能富集泡泡图
- Git:如何在本地没有分支时,切换分支
- libgdx 3D CameraInputController WASD控制器
- MFC中获取各个窗口(对话框)之间的指针、对象、句柄
- 为工大瑞普新编写的CCNA实验手册提供下载
- 简单的豆瓣电影推荐系统demo
- 基于JEECG框架,前台VUE,后台java,导入导出
- PTA-今天是本学期的第几周的第几天?
- 手机APP测试——Perfecto
- web前端开发和后端开发哪个好?
- OpenCV钢铁平面焊接的缺陷检测案例
- ArduPilot开源飞控系统之简单介绍
- JS判断字符串中的内容是否为纯数字
- 什么是Apptainer?如何在Ubuntu服务器上安装?
- 公司给股票期权,我买还是不买?
- 用手动Ghost重装系统(gho镜像)
- date类型的时间转换成年月日格式
热门文章
- Excel 划分各分数段并统计各分数段的人数
- android开发常用工具类、高仿客户端、附近厕所、验证码助手、相机图片处理等源码...
- 帮我用js写一个微信聊天那种气泡效果
- hdu 6078 Wavel Sequence
- -fpie -pie_Google的Pie Noon,TI-83上的Super Smash Bros等
- 了解掌握Java的循环语句、条件语句、分支语句(Java 从自学到就业 第3天)
- vue实现在线编辑excel(转)
- 语音控制Office,这个功能一定要体验
- stm32学习笔记---STM32F4知识
- 【Devc++】战斗1.0.1