Diffuse: 如何做一个类似于 Apple Music 的假流体壁纸

 • 

其实 Diffuse 最后做出来的效果和 Apple Music 的 Live Lyrics 效果不太像,因为后期我也不管苹果的效果如何了,完全按照自己的喜好来调的。而且 Apple 的方案比我的要 versatile 很多,这个词可能比较在描述软件的时候有特定的内涵,导致我也不知道中文要怎么描述了,反正和鲁棒差不多,但是更多的是指对不同的输入都有类似的效果,因为我的方案在纯色封面时效果会特别差,输出的图像没有对比度,Apple Music 的效果会好一些,所以我怀疑他们对图片是有在做预处理,或者压根没有对封面做模糊而是直接根据封面提取出一个色盘后做了渐变。
Diffuse 的基本思路就是对专辑封面先模糊再扭曲。一开始模糊用的是全分辨率高斯模糊,一个纵向 pass 一个横向 pass。后来发现太费资源了,于是改为了马老师(MartinRGB)推荐的 Kawase Blur。有关 Kawase Blur 的详情可以看 Intel 的这个博客,我是在 LibGDX 内实现的,这段从哪来的也忘了,估计是某个 ShaderToy(

// kawaseBlur.frag

#ifdef GL_ES
precision mediump float;
#endif

uniform sampler2D u_texture;
uniform int u_level;
uniform vec2 u_resolution;

varying vec4 v_color;
varying vec2 v_texCoord;

vec4 reSample(sampler2D texture, vec2 res, in int d, in vec2 uv)
{
    vec2 step1 = (vec2(d) + 0.5) / res;
    vec4 color = vec4(0.0);
    color += texture2D(texture, uv + step1) / float(4);
    color += texture2D(texture,  uv - step1) / float(4);
    vec2 step2 = step1;
    step2.x = -step2.x;
    color += texture2D(texture, uv + step2) / float(4);
    color += texture2D(texture,  uv - step2) / float(4);
    return color;
}


void main() {
    gl_FragColor = reSample(u_texture, u_resolution, u_level, v_texCoord);
}
// kawaseBlur.vert

uniform mat4 u_projTrans;

attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec4 a_color;

varying vec4 v_color;
varying vec2 v_texCoord;

void main() {
    gl_Position = u_projTrans * a_position;
    v_texCoord = a_texCoord0;
    v_color = a_color;
}

关于 kernels (u_level) 我选的是 0,1,1,2,2,3,3,4,用了两个 192*192 像素的贴图 squareBufferA 和 squareBufferB 互相渲染,效果还不错,性能在高通 8xx 上都没遇到太大的问题。

blurShader.begin();
blurShader.setUniform2fv("u_resolution", new float[]{squareSize,squareSize}, 0, 2); // squareSize 就是 192
blurShader.end();
batch.setShader(blurShader);
int[] levels = new int[] {0,1,1,2,2,3,3,4};
for (int i = 0; i < levels.length; i++) {
    int level = levels[i] * 2;
    boolean swap = i % 2 == 0;
    blurShader.begin();
    blurShader.setUniformi("u_level", level);
    blurShader.end();
    batch.begin();
    if (swap) {
        squareBufferB.begin();
    } else {
        squareBufferA.begin();
    }
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    batch.draw(swap ? squareBufferA.getColorBufferTexture() : squareBufferB.getColorBufferTexture(), 0, 0, width, height, 0, 0, 1, 1);
    batch.flush();
    if (swap) {
        squareBufferB.end();
    } else {
        squareBufferA.end();
    }
    batch.end();
}

blur

然后就是扭曲的过程了。这个部分用的是 Domain Wrapping,基本上就是照着 iquilezles 来了,最后得到的 vec2 作为 uv 去 sample 之前模糊后的专辑图

noise

然后就可以放大分辨率输出到屏幕上了,就这么简单(

2020.4.21

 • 

准备早睡的,但是又一次睡不着。刷了下新闻,原油价格都变负数了
总觉得是什么了不得的事情,但是又说不出来,毕竟自己也只是一个迷茫的,靠写点小软件找乐子的普通人,对这个世界上的其他东西都没什么实体的概念,看到消息也不会跳起来去操作什么期货终端,只是觉得今年的事情真的多啊
要说睡不着的原因,可能牙疼算是一个。总觉得今年会再拔掉一颗烂牙,但因为只是有的时候才发作,因此自己也不置可否,还是无节制地吃巧克力。偶尔在被窝里咽口水的时候能感到缺口穿过空气时微妙的酸痛,像是从空调房突然切换到室外,短暂一阵子就又习惯了,呆滞了几秒钟后就又翻个身子继续胡思乱想
拖了很久没写博客,原因是前段时间在纠结选什么学校。其实到最后就只用选东北大学 MSIS 和纽约大学 MSCEI,个人倾向还是纽约大学,但一年项目外加目前的疫情对找工作这个长远目标不太友好,因此只能安慰自己东北也很不错了,而且多出来的时间可以把游戏开发完。
于是想着可以写个申请总结了,甚至在 Ghost 的后台开了一个 draft 题为 20 fall 申请总结。但又觉得提不起兴趣,毕竟不是什么凯旋而归的结局,对于我来说已经决定就 move on 不提也罢。短短地说的话,今年的总结大致就是低 GPA 的 CS 本科生申请 master 就把自己当成转专业的人来选学校,心态和结果会好很多。我没绕过这个弯,虽然没有死磕 CS 但是还是申请了好几个 Professional CS 或者 Course based MCS,结果只有一个过的 UMass CS。此外,当时还是不够大胆,也不够果敢,本来自己的经历就这么不寻常了,申请的时候还可以多加点戏妨碍不了什么,比如再加十个学校申请把头部学校的偏门项目轮一遍,比如被 rej 了立即写信求转项目,这些都是当时觉得不太好吧所以没去做的事情,现在看没什么大不了的。
啰嗦完这个感觉我的总结草稿可以删了,很多时候倒不是没有写作的心情,而是前方总是有要做的事情,让我感觉做完才有资格能去写博客介绍我干了什么,或是有什么我不想做却又必须要做的事情,拦在前面让我每次想去写博客的时候觉得还不如先把讨厌的事情做完。如此往复写作的乐趣和期待就开始消失殆尽了。
写独立软件也是,一旦套上挣学费这么一个目标,就很难再开心地做下去了,而且还会被别人的灵魂拷问问得自己也怀疑人生。是,以之前尝试做跨平台 markdown 编辑器的我来看,目前做的这些项目都是上不了台面的 Personalize 软件,甚至连 Utility 都不算,但也是因为之前在这个领域有点经验,觉得也许能复制点结果。话说回来,挣学费这件事情,也完全是我自己给自己套上的一个附加目标,我也总喜欢自己给自己这么加戏,力求成为想做什么就能做到的人。
但是本科的前半段的时候我的目标还没这么现实,当时的想法更多的是想做 100rabbits 他们那对 couple 在做的事情,就是开着小船环游世界,船里带着台笔记本,开发各种自用的东西,从小型操作系统到 2D 游戏到相机软件,不管别人用不用得到,自己开心就好。然而那种存粹的乐趣,在我经历很多事情后或许也很难再有了,只希望东北这个两年的项目,能让我在去美国搬砖之外,给我留出一点时间再去做类似的事情,看在学校的生活永远比外面的要单一的份上。
爬起来敲了这么多,到最后公布下之前提到过的 libGDX 项目的网页好了。Diffuse 按理说一周前就应该上架开始推广了,然而因为 Play Store 审核时间变长,目前还处于半上架的状态中,让我卡在不知道要不要准备 presskit 的尴尬境地中。我对这个项目还是挺喜欢的,喜欢到甚至想把这个移植到个人电台 fin.fm 的推流端里去,这个想法反而有点像是有那种自做自用的精神了。
然而全世界那么多人,我也无法保证到底大家的口味如何,究竟令我着迷的这些事情在其他人眼里算什么呢?就像是我放弃的事情在有些人眼里也不可理喻一样。不管怎么说,把自己当个普通人会让这些事情好理解很多,大家都是普通人,在不同的路上周游世界而已,没有什么要比的,这个世界或许就是太容易让人从头到脚互相打量了,反而开一个 echo chamber 会自在一些。

2020.4.10

 • 

Vortex 之前因为 Awareness API 移除天气数据几乎变废了,还好 Yahoo Weather API 可以非商用的前提下免费试用,最近申请通过了,花了一下午迁移了过去,新版本几小时后就会更新到 stable channel 里。
Metropolis 增长依然比较乏力,在 Sam BeckmanGadget Gig 的两个推广视频后有增长,Google Play 的个性化定制这个分类里能排名到新增榜前五,畅销榜前一百,但 that is it,后来就开始掉了,我也不太想再找其他的曝光机会了,投入过大不值,就先这样放着。
之前的博客里还提过一个基于 Rajawali 的项目,后来改成 libGDX 做了,已经在内部测试中了,感觉大家的反响都还不错。只是因为疫情的原因 Google Play 的审核变得特别慢,因此到现在还没有真正发布。

2020.3.25

 • 

找到了一个电影评论的频道 Jack's Movie Reviews,结果看上瘾了,连看了好几个。这种情况越来越少了,之前大学的时候经常碰到好频道,订阅后扫之前的历史投稿能在宿舍里懒在靠椅上看一天,比如 videogamedunkey,lesson from screenplay,escapist 的 zero punctuation 系列,等等。这个频道说借刀杀人的那一期挺合我意,因此还专门给那一期配了中文字幕。可惜的是后来才发现这个频道已经停更了,貌似是因为作者找到了一个实习。
说到停更,h3h3productions 今天倒是久违地一年之后突然更新了一部。YouTube 的推荐算法有的时候还是能给我推荐他们以前的视频,我对他们的价值观还挺认同,比如要大家 chill out 的这期。此外,他们还有很多搞笑的回忆,都是看后能让人放松的视频。

2020.3.20

 • 

天气开始变热了。穿着睡衣在家里写东西的时候经常暖和得很烦躁。
最想去的一个项目给我 rej 了,剩下的要么比现在拿到的最好的 offer 同级要么靠后,因此目前也可以准备决定去哪了。不管怎么说,对于一个本科 GPA 超低的人来说,今年已经超过预期了,所有对之前没有多申请点好学校的后悔都是事后之言,放几个月前我也是不敢对父母保证的。


天气变暖后,莫名地感觉和大学入学前的暑假气氛很像,也是一个看似无忧无虑,实际上也许需要我提前做很多准备的时间。已经有同样录取的人在刷题群里聊天,而我呢,虽然知道要去刷题,但是还在做严重延期的几个项目。
基本上这些项目分为两类,一种是独立软件,希望能快速地重新实践下 Skyline 推广被报道的经验,提前挣一些美元当生活费。然而 Metropolis 的增长并没有达到预期,或者说 Skyline 被报道本身也只是无心插柳的一次成功。因此目前手里还有一个基于 Rajawali 的项目,留着快速开发再试一次,如果还是不行我也就放弃独立开发挣生活费的想法了,转而刷题准备当地的实习。
第二类就是独立游戏。Epoch 已经准备从头开始写了,不过 2016 到现在 Unity 的生态和主推技术栈也改变了很多,再加上目前的 Unity 是一个各类框架都在交接的状态,UI 方面 UI Elements Runtime 要到 2020.1 才有预览包,UGUI 不想用,UIWidgets 又太专注 flutter 的 render to quad 模式,不足以支持特定的 3D UI 需求;渲染方面 LWRP 到 URP 还是鸡飞狗跳,选 legacy pipeline 又怕后期 Unity 直接宣布弃用,接着 Runtime GI 也是 2021 的排期了。倒不是说前期就要做视觉效果,我也可以直接先什么都不管只做数据层,但总是觉得少了很多信心和乐趣。
感觉几个项目在投入和放弃的取舍上都已经不是自己真正想要的了。或许等到下次写博客的时候,能带来一些有趣的消息。

2020.3.13

 • 

最近又陷入了坐立不安的情形,修 Metropolis bug 的时候想打游戏,打 Forza 的时候又觉得不妥,想去把 WWDC 的申请写了或者开始做 Epoch。想起来之前博客上写过实习的时候一旦觉得不自由了就会到处折腾让大家不高兴,现在其实也是差不多的情况。
理论来说现在的确有很多事情要做,比如驾照和刷题,但是又觉得申请的最终结果尚未决定,况且目前各地的情况也不明朗,做事的意义也不知道在哪,因此总是懈怠下去。


Metropolis 做了一些 PR 的工作,但是效果只能说一般,当然原因也是本身软件还有很多我自己都觉得不满意的地方。因此自己总是在做新项目和修 bug 中间来回。关于 WWDC 奖学金的申请,今年想做一个 SwiftUI Prototype Tool,结合去年的节点编辑器,通过节点生成对应的 SwiftUI struct,中间通过 codable 转接。但是后来仔细想了下貌似意义又不是很大,所以也只是开了个头就没投入了。


UniLWP 在 Metropolis 投放的过程中发现和一加手机在 Android 10 上严重不兼容,具体表现就是对 unityPlayer 调用 displayChanged(0,null) 或者 pause 的时候经常超时,导致 ANR 被系统砍掉。原本以为是 call rate 的问题做了一个 debounce,但是看貌似也没用,于是后面考虑利用 Unity 的多显示器支持,把不同的 surface 作为不同的显示屏幕传入 displayChanged 里,避免和主要的 Display(即 index = 0)交互,但是试了下貌似也不稳定,而且每次调试都要生成 jar - 打包 apk - 上传到阿里云云测 - 复现抓 log - 下载下来看,这又是特别消耗 san 值的事情,因此现在已经不想碰了。


所以现在就漫无目的地翻看网页,偶尔查下录取结果,期待某个时候能灵光一现,让我能去做点具体的事情。我还是挺喜欢做这些细细碎碎的写软件的差事的,就是最近太把兴趣当成业务来做了,还是跳票的生活舒服些。

2020.3.6

 • 

距离上次写博客又过去一周了,过得真快。


移动硬盘因为笔记本莫名其妙内核恐慌断电跟着出现了问题,怎么修复也修不好,索性不管了。硬盘里面装着大约 12 年到现在存下来的四五千首歌,损失倒是挺惨重的,虽然云端貌似还有着一份备份,但是是最近一次整理 ID3 信息之前的了,想想就头痛。自己的个人项目存在了另外一个硬盘里,倒是没有受到太大影响,不过也因此停滞了两天的工作。


Metropolis 的官网上线了,页面内的视频也是最近渲染好的。网站里面用 babylon.js 做了一个小型的软件模拟,可以模拟解锁的三维动画。这个写起来比之前 Skyline 的那个要容易很多,因为 Skyline 那次是 three.js,手机本身也不只是个矢量图而是真正的模型,因此当时又做了个 render texture 来模拟手机显示,现在看真的是玩票性质的。


听了 Panini

23

 • 

Metropolis 原计划在 23 岁的生日当天发布的,结果因为一个奇怪的 WallpaperManagerService 相关的问题(和 PackageManager 在更新软件时冻结和重启 package 的 race condition)推迟了一天,并且即使目前 Metropolis 正在通过 Google Play 的 CDN 分发到各地,它仍然只是一个不稳定的,占用大量内存的,feature set 只实现了原本三分之一的,官网都还没搭建完的,beta 版软件。
但是 Metropolis 的视觉看起来很棒,这就够了。👇

photo_2020-02-26_06-17-46
Metropolis(中文名 -> 大都会)是一个基于 Bing Map 的三维城市动态壁纸,提供北美主要城市的三维模型,你可以把 Metropolis 当成 Skyline 的姐妹版。同时如之前所说,Metropolis 是 UniLWP 框架的第一个成品,框架也在开发产品中反向贡献了很多新功能,接下来就是稳定性的验证了,时间到了 UniLWP 自然也会上架售卖。目前可以通过 Google Play Beta 加入公开测试。


接下来重心会转一下,因为我还有两件事情没做,一个是 WWDC 20 的奖学金申请项目,一个是 Epoch 的开发。前者大约需要一周,后者目前预估的是明年的第二季度能完成 gameplay 的部分。但是考虑到 Metropolis 这么一个预估一周开发完的东西折腾了我三个星期,我现在也不敢对任何事情打包票了。
此外,留学申请目前是三个 ad 三个 rej,最早的暑假就入学,而如果最后要选择这所学校的话,Epoch 就要更加往后推了,因为要提前刷题准备当地找工作。


以上就是目前的规划,虽然回头看,自己在 20 出头的前三个年头基本上没有一次按照规划来的。20 岁的我写了篇 20,担心着自己的价值会不会像是超市的商标一样浮动,又说了自己的幸运之处,虽然后来看没过几天就做了让自己掉价的选择。21 岁的我写了篇 21,讨论着没钱,尚不知晓两周后 Skyline 会让自己赚一笔。22 岁我的我什么也没写,处于固执己见又难以自己证明给自己的阶段,现在看只是突然失去了目标。
等待申请结果又因为疫情而慢下来的时间里,我和我妈复盘过大学的这几年。让她欣慰的是虽然大二闹着要退学,大三近乎逃学,毕业后又毁约大厂又参与创业又出走算下来 gap 了两年,至少现在有了研究生的 offer,也没有落下来多少。而让我欣慰的是,家人还在支持自己,这几年虽然吃了不少亏,但是过的也很有趣,更重要的是断断续续地,总会有事情让我觉得,只要我想做就能去做成功。
这句话听起来很俗,但要知道,持续的心想事成可是超人一般的能力,或者说天赋也不为过,而且这种正反馈只会越来越大。所以我很感激意气风发的光景,不管是实习的时候,打 hackathon 的时候,还是做独立软件的时候。但是也因为太在意保持这种惯性,一旦走错了路我就会开始怀疑自己是不是失去了那种特质,直到下一轮不知道什么事情再把我带回轨道上。


我曾经很喜欢 Livid 的一句话,我也忘了具体怎么说的了,大致是他在博客上评论了不起的盖茨比,然后说真正的盖茨比是不会让悲剧发生的,因为他会一直和自己较劲。当时看了觉得真好啊,现在再看,又多了些感慨,或许是因为明白过来盖茨比的设定本来就有原罪一样的东西,而自己曾经和很多一样自比盖茨比的人一样相互碰撞,头碰血流,谁也不服输,最后总有要下场的,落败的盖茨比。
而我是,至少是暂时,还是不想当一个下场的。
这或许就是我这一年尽力要做的事情了。


听了 tatsuro yamashita - come along IItoshiki kadomatsu - summer time romanceUnnatural CitySeptemberWorrying StateSoulection Radio Show #274 w/ Mac Miller 看了 Hitman 2: The Rise of Agent 47Vue.js: The Documentary

2020.2.12

 • 

Metropolis

Metropolis 的工作完成一半了,这将是用 UniLWP 完成的第一个 LWP,很多在 Metropolis 中的脚本也将 backport 到 UniLWP 里。

 • 

半夜睡着觉 突然显示器自己亮了起来 把整个屋子都照亮了
显示器上空荡荡的只有壁纸 迷迷糊糊地以为自己还在做梦 盯着显示器看了一会 突然反应过来是不是有新的邮件通知 于是蹦起来去检查邮件 看是不是有其他学校录取我了
然而什么也没有 于是我关掉显示器 整个屋子又变黑了起来
我坐在床上 听着楼下的猫在发情地叫 想着自己仅有的好消息 渺小的未来 和外界源源不断的坏消息