23 年兔年,五福项目将传统的写福字升级成了年画,用户通过绘制兔子轮廓可以得到活动的兔子,同时由 AI 生成对应的兔子年画,整个过程给用户带来很强的惊喜感,同时将具有传统氛围的年画与科技感拉满的 AI 作图有机结合,为大家带来全新的年俗体验。
AI 年画作为 23 兔年五福的创新项目,在玩法和技术方案上都采用全新的实现,前后端技术、AI 算法深度,以及美术互动等深度协同,实现了玩法了技术的双创新,最终呈现的效果得到了广泛的认可。
1. 年画介绍
1.1 背景:利用科技,制造「眼前一亮」感
-
科技集福,让用户有眼前一亮的感觉 。 集福除了写福、扫福外,还有AI福(爱福,谐音梗),将主链路的集卡跟当下社交网络刷屏的AI作画结合( https://www.huxiu.com/article/540962.html ),一个词一张画一个福,让用户体验到有当下科技力的玩法形式。
-
个性化福卡,五福也可以私人定制 。 五张福卡所有用户是统一样式,但用户对于能传播的介质个性化追求越来越高,通过自己的关键词生成新年运势画,变成一张独一无二的福卡,能更好的让用户有收藏感(可以支持制作NFT)和分享感。
1.2 玩法介绍
一句话介绍:用户根据引导画出兔子轮廓,根据轮廓生成AI福兔,福兔结合装饰套组生成福兔年画,并可以对应的虚拟和实体物品。
此处为语雀视频卡片,点击链接查看:normal video.mp4
1.3 创作页
用户在创作页完成年画兔子的创作,同时请求服务端生成对应的 AI 年画,最后通过转场动画过渡到装饰页。
-
画布上按顺序出现兔子身体各部分的绘制引导,用户在引导底纹的范围内绘制兔子的轮廓。
-
在用户完成当前轮廓的绘制后,依次出现下一个身体轮廓,直至完成绘制。
-
用户在完成一部分兔子身体后,绘制完成的兔子身体会做出对应的动作,如画完两只耳朵后耳朵动一动。
-
用户可以选择撤销当前绘制的内容,支持回退到上一笔的绘制。
-
每隔一段时间页面会出现引导用户绘制的高亮提示,长时间未完成绘制时出现自动绘制的气泡。
-
完成绘制后点击按钮进入合成动画,生成 AI 年画,切换到装饰页。
1.4 装饰页
用户在装饰页使用各种素材贴纸 DIY 装扮自己的年画,为自己的年画署名,或是选择重新创作。
-
用户可以从下方的贴纸栏中选择素材 DIY 装扮年画。
-
用户也可以点击重新画按钮,生成新的年画。
-
在完成装扮后点击完成生成最终的年画,同时跳转到年画主页(作品集页面)。
1.5 主页
用户在年画主页可以查看自己创作的所有年画,同时可以选择保存、分享自己的年画作品。通过下方的栏目还可以选择获取自己创作年画作品的周边以及对应的数字藏品。
2. 技术方案
2.1 整体架构
年画项目采用多页面,整体技术页面 (html) 跟视觉页面保持一致,只有互动相关的页面(创作页和装饰页)在一个页面里。互动相关页面分成游戏层和 React 组件层,通过 mx 的事件机制进行通信。
2.2 技术选型
兔年五福年画项目作为一个 2D 互动应用,选择 TinyJS 做为渲染引擎,同时选择一系列 Tiny 的插件库。TinyJS 在支付宝业务中广泛应用,经历多年互动业务落地沉淀,是目前支付宝 2D 互动的首选。
2.2.1 生态工具
TinyJS 拥有丰富的生态,今年的年画项目中使用了一系列插件来完成各种功能模块的开发。
-
tinyjs-plugin-calligraphy 历年五福的书写插件,让用户实现自由书写。
-
tinyjs-plugin-transformable 贴纸操作插件,让用户选择贴纸自由装扮年画。
-
tinyjs-plugin-ui 提供便捷的 UI 绘制能力。
-
tinyjs-plugin-extract 提供通用的图片合成、导出能力。
2.2.2 特效选择
mars 动画是实现各种炫酷的特效的首选,同时也是今年的五福规范,在 TinyJS 作为渲染引擎的背景下我们使用 tinyjs-plugin-mars 播放 mars 动画。
Mars Studio工具制作动画
2.2.3 动画选择
为了让兔子在画布中动起来,我们选择使用 spine 实现兔子的骨骼动画,在 TinyJS 中使用 tinyjs-plugin-spine 骨骼动画插件实现。
2.2.4 简单动画
为了减少内存和预推资源的消耗,我们在一些部分动画上选择使用 shader 的自定义动画,同时保证性能和效果。
2.2.5 开场视频
此处为语雀视频卡片,点击链接查看:720P_h265.mp4
视频处理
现在画眉直接就可以进行压缩和上传 cdn 的步骤,所以现在拿到原视频之后,上传到画眉就可以拿到压缩后的 cdn 地址了,可以根据需要选择使用的链接:https://yuque.antfin.com/huamei/help/cx3i9t#aP4W9。
关于整个五福的视频使用方式可见:https://yuque.antfin.com/qffd8u/hwk0ns/gpgnwub9qvotggws
视频使用
在开场视频的选择上我们采用@陌诗提供的同层组件--@alipay/fu-video-player,相比于一般的 Video 组件来说,该组件会自动对非安全区域进行剪裁,保证了视频在不同机型全屏播放都能展示比较好的效果。
具体的的实现逻辑可见去年写福字的逻辑:https://yuque.antfin-inc.com/fui/wufu-hu/gwdiv5#gPZRx
2.3 开发实现
年画的玩法有一条明确的动线,那就是绘制兔子,生成年画,装扮年画,年画作品集,因此在开发我们可可以整个互动分成四阶段:
-
paint(绘制阶段)用户在画布上按照提示绘制年画兔子。
-
transform(合成年画)请求服务端返回 AI 生成的年画,过渡到装饰页。
-
decoration(装饰阶段)使用各种素材装扮年画,确认生成后跳转主页(作品集)。
-
home(年画主页)用户创作年画的作品集页面,统合了年画、福卡、周边、NFT 等所有内容。
2.3.1 创作页
创作页主要的难点有两个:
-
一个是让引导绘制的兔子轮廓动起来。
-
自动绘制。
让引导绘制的兔子轮廓动起来
最开始的产品方案其实就是让按照步骤描轮廓,大致的交互如下:
为了增加趣味性, 参考了其他的绘画 App,需要在绘画的过程中和绘画完之后兔子的部件(耳朵、手、脚)要动起来,这无疑增加很大的难度(因为这是第一次需求评审完之后才变更的,这给设计师和前端开发都会带来巨大的工作量)。
此处为语雀视频卡片,点击链接查看:3.mp4
如果要让绘画的兔子每个部件动起来,首先想到的就是需要用骨骼动画,蚂蚁推荐的就是用 Spine 去做(这部分是设计师做的)。
此处为语雀内容卡片,点击链接查看:https://yuque.antfin-inc.com/ant-galaxy/igbook/dafu0y#XkYLe
骨骼动画确实是可以动,但是怎么将绘画的轮廓跟骨骼动画结合起来了,这个在蚂蚁,甚至业界目前看来没有现成的方案的。
具体的方案探索
1)骨骼动画支持换肤,可以将用户的画的笔迹提取出来作为骨骼去进行换肤。
换肤的大致流程就是设计师在设计动画的时候挖一个坑,专业名词插槽(slot),加载 spine 动画之后,开发可以把图片通过插槽名对原来的插槽部分进行替换,这样就实现了换肤。详细可见:https://yuque.antfin-inc.com/ant-galaxy/igbook/dafu0y#3TD9i
所以设计师在设计的时候就需要把哪些要动并且进行可以替换的地方,做成插槽。
2) 如何将用户画的部件精确的提取出来
一开始业务期望是一个可以任意画的画板,用户随意画,但是我们无法识别出来用户画的笔迹哪里是耳朵、哪里是手、哪里是脚,识别不出来,就更别想提取笔迹进行替换了。
为了可以识别出来在画板里哪部分是耳朵、手、脚,我们需要对用户的可绘制区域和绘制顺序进行限制,限制出哪部分是耳朵、手、脚,用户在我们圈定的地方绘制的,我们就认为是该部件。
比如左上角圈定一块区域,我们就认为是左耳朵,这部分提取出来的纹理,在进行换肤的时候就换肤到 spine 动画的左耳朵处。
为此我们实现和设计师制定了统一的坐标系,实现笔迹提取范围和美术资产的对应,保证绘制内容到 spine 骨骼的无感切换。
所以我们跟设计师约定了大致这么一个范围,来确定插槽的部分。
3)如何让动画动起来好看
虽然我们约定了笔迹提取范围,可以识别出来身体部件,但是用户如果在这个框里画出来不像我们期望的样子,这样就会导致两个问题:
-
兔子画出来不好看。见下图对比
-
兔子动起来的时候关节与关节非常有割裂感。
所以为了解决不好看的问题,我们还得限制,尽量保证我们引导用户画耳朵,就画出来像耳朵。
两个解决方案来保证这个问题:
-
增加引导底纹并限制用户绘制区域。
-
在这个区域绘制出来的笔迹,尽量像引导的底纹才能画下一步。
限制用户绘制区域:
设计师在给引导的兔子部件底纹的时候,还需要给一份部件的轮廓坐标。
这样我们就可以利用轮廓点位,通过 Tiny.Graphics 绘制一个 Mask 区域,盖在画布上,相当于把轮廓外面的都设置了 mask,超出轮廓的笔迹都看不到;并且保证了用户绘制内容的可控。
看标记的地方,明细能看出超出的部分别截掉了。
在这个区域绘制出来的笔迹,尽量像引导的底纹:
如果按照我们限制绘制区域画出来,基本上画出来的兔子已经很像了,但是有可能用户在这个区域里没有画完,可能只随便画了一笔,这样可能不是很像,所以我们还加了一个粗糙的相似度检测。尽量的去保证用户画出来的笔画是我们预期的效果。
具体的方案就是判断笔迹的路径是否通过我们预设点的大多数(目前是 80% 的点位)。所以设计师还需要给一份兔子部件的点位,见下图。
在笔触移动的时候通过碰撞检测,检测是否经过预设的点位,超过 80% 的点位,就认为完成当前部件的绘制。
到此,基本上就能保障用户画出来的兔子默认好看,并且动起来的时候也好看。
自动绘制
为了提高绘画成功率,有些用户不知道怎么操作,或者懒得操作,提供了自动绘制的功能(可能有些同学还不知道有这个功能),在用户一段时间没操作的时候会出现自动绘制的提示。
绘制我们用的 tiny-plugin-calligraphy 插件,该插件本身并不支持自动绘制能力,在分析插件源码后通过事件代理的方式最小成本的实现了自动绘制功能。
要实现自动绘制很关键的两个点:
-
绘制的点位顺序。
-
当前用户绘制进度在哪里?
绘制点位的顺序:
这个在前面已经给过了,就是这个,只是给的时候需要注意一下顺序即可,通过数组的方式保证顺序。
当前用户绘制进度在哪里:
因为在给点位的时候是每个部件一份数据,而不是一份完整的兔子轮廓数据,还需要每个部件合起来定义一个顺序。同时,如果用户画到一半,然后再想用自动绘制的时候,需要知道当前自动绘制应该绘制哪个部件。
我们将兔子身体划分成六个部分,分别是左耳、右耳、左脸、右脸、左身体、右身体,通过标志符判断用户的绘制进度,同时使用标志符管理绘制阶段。
定义好之后,就按照 drawIndex 进行自动绘制即可。
2.3.2 合成年画
在切换装饰页时,我们通过一整套完整的动画流程来保证用户体感和引导的连续性,兼具趣味性和科技感。为此我们在各个节点上设置了相互衔接的不同动画。
兔子首帧出现和年画溶解出现的动画效果,使用了 Tiny.Filter 提供的自定义着色器能力,通过自定义的 shader 代码实现高性能动画。
在具体实现溶解效果的时候,将连续的灰度分布图作为底图,在着色器中根据连续的采样结果 + 线性偏移的时候。
2.3.2 装饰页
用户在装饰页完成年画的 DIY 装扮,生成最终的年画。
整个 DIY 过程主要用到了 tinyjs-plugin-transformable 插件实现贴纸的编辑(拖拽、旋转、删除、镜像、缩放)。
再装饰完成之后使用 tinyjs-plugin-extract 插件导出年画和年画前景。
2.3.4 其他
高清合图
年画项目还为用户提供了一系列的年画周边,如挂历,马克杯,地毯等印有年画的商品,为了保证周边商品上年画的清晰度,我们需要再实现一套额外的高清年画合成方案,为周边商品提供大尺寸的高清年画。
我们在装饰页 DIY 年画的过程中,会记录兔子,背景,贴纸等素材的位置大小和角度,根据位置和大小信息使用原本素材的四倍图在合成年画的高清版本。
此处为语雀内容卡片,点击链接查看:https://yuque.antfin.com/yspkbi/qo5h51/bguhq8
受限于现有打印链路的能力,我们使用多媒体团队提供的 SVG 合图方案,而在年画创作 DIY 和时候使用的是 TinyJS 以及 tinyjs-plugin-transformable 插件的混合坐标体系,与 SVG 坐标体系不兼容,为此我们需要写一套额外的坐标转换逻辑,同时后端还需要将前端提供的坐标转换逻辑再转成 Java 实现,最终在后端实现合图。
该过程非常的痛苦,调试了至少 3 天才把整个链路调通,期望未来有一套 Canvas 坐标标准的高清图合成能力 @写轮。
降级
为了覆盖 100% 的用户,尽量保证效果,我们就用户不同的终端情况实现不同的降级逻辑。我们通过 jsapi 接口 getDowngradeResult 获取降级信息。
-
视频降级
-
WebGL 降级:当终端不支持 WebGL 时,页面互动降级成 Canvas 模式,同时不再播放骨骼动画。
-
Mars 降级:在终端不支持 Mars 或是 Mars 播放器创建失败时,使用贴图进行兜底。
-
低端机降级:在低端机上使用 Canvas 模式,预计降级设别占比为 2%。
2.3.5 不同场景使用不同规格的图片
年画的使用场景很多,不同的使用场景, 比如壁纸、付款码皮肤、红包封面、NFT ,不同的场景需要的图片尺寸还不一样。
-
年画尺寸:750 * 975
-
壁纸:需要的尺寸是 750 * 1624 的
-
付款码皮肤:需要单个兔子 、年画前景 750 * 975 (不需要年画背景)
-
NFT 和红包封面:最终年画即可
提示:尺寸为了统一,都以 750 宽度为基准,虽然最终生成的年画是 600 * 780,这个跟 750 * 975 比例是一样的,为了好理解,文中 750 * 975 和 600 * 780 可以互相替代,不影响理解。
所以为了看起来是一个年画,但是要适应不同的场景,整个方案如下:
以学生兔这样的一个年画为例:
算法会给三张图片:长背景、短背景、兔子,前端负责剪短背景、合并兔子和吉祥话到画板中。
用户在完成 DIY 装饰后导出最终年画和前景图。
现在就有了适用于各种场景图片的原始图了,对于年画的业务方就根据需要使用即可。
2.4 难点与技术细节汇总
-
画布和美术资产坐标系的统一,实现视觉稿、模型资产(spine、mars)、前端数据准确匹配。
-
用户笔迹纹理提取,并动态替换到 spine 骨骼中。
-
兔子自动绘制的实现
-
AI 年画绘制画笔选择 tiny-plugin-calligraphy 插件,该插件本身并不支持自动绘制能力,在分析插件源码后通过事件代理的方式最小成本的实现了自动绘制功能,同时让自动/手动绘制的兼容,实现自动/手动绘制的任意组合。
-
合成动画、转场
-
转场动画需要加载大量的美术资产(spine,贴图),同时需要向服务端请求 AI 年画图片,为了保证用户的体验(弱网情况保证较短的等待时间),我们做了诸如提前加载、重复动画播放等方法保证转场动画的连续性(动画体感无等待)。
-
在合成动画期间我们使用了 spine 骨骼、动态合成年画、基于 tiny filter 的 shader 动画,简单位移动画等一系列的动作进行组合,在各个独立功能都无法保证 100% 成功率的情况下,我们需要为每个动作设置兜底,从而保证复合动画效果的相对稳定。
-
AI 年画的溶解出现,在合成动画中我们实现了基于灰度图的溶解特效,让美术只需要调整静态的灰度图片就可以任意调整溶解特效,极大的节省了视觉效果评估的修改成本。
3. 线上数据
-
AI年画累计作画成功用户 1.3e ;累计作画次数 2.8e ;人均作画 2.2 张(同比 +17.6 %,去年写福字 1.87 张)
-
分享年画得福卡活动参与率 x% * 分享uv/作画成功uv (同比+x%)
-
带动合作业务情况如下:年画红包封面参与用户 xxx w(占年画整体 x%,符合预期);年画数字藏品领取用户xxx.xx w(占x%);印鸽服务商周边打印订单量共计 xxxxx单;
4. 明年五福的建议
-
需要对常用库进行统一,避免一些不熟悉移动端的同学选错组件或者手写没有经过验证的组件。 比如常用的轮播、剪切板、走马灯等 ui 组件进行统一,今年年画主页的作品集其实是自己手写的一个 swiper,在群体 cr 的时候发现了,在 ios9 的时候是有兼容性问题的。所以最后还做了一个降级方案,如果提前能把这些常用库统一,可以避免一些这样的问题。
-
需要封装一套常用的 util 库。 比如 jsonp、screen、支付宝版本比较这种常用的 util 方法,目前还是通过互相拷贝代码或者抄去年的代码,或者手写。
5. 感谢
AI 年画项目的离不开所有为此努力的每一位同学,在此表示衷心的感谢! 产品:@蕃薯
视觉:@秋也 山海 王金雨
交互:@真蓁