一时兴起给弹幕界面搓了个星空背景
📝2435 个字
 | ⌛要看完怎么也得7分钟吧
背景概述
- 就在前几天,没事瞎逛博客的时候,突然意识到咱这小网站虽然叫做《🌟星野の隙間🌟》,但好像主页上除了标题以外,一点和🌟有关的内容或者装饰都没有🤡。甚至随便换个名字,感觉都毫无违和感🤣。
- 所以经过一顿的脑暴之后,感觉是时候整个相关的装饰物了。但是咱这小网站还是内容主导的,所以本就已经满满当当的主页上,不是很想再额外增加装饰物,万一用力过猛了,搞不好就喧宾夺主了🤣。
- 就在这三千烦恼丝,又要折损几员大将的时候,突然想起之前因为在无意间发现,cloudflare的Durable Objects功能有了免费额度。所以怀着熟悉一下功能框架的同时,锻炼一下代码能力的心态,最后手搓了一个自用的弹幕系统。同时为了能在网站上接入,又专门增加了一个用来发送弹幕的界面。具体内容如果有小伙伴感兴趣的话,可以直接看这篇文章。
- 然后在打开发送界面的时候,为了能够突出弹幕和操作区域,当初索性给全屏增加了一个大黑蒙版。诶,就是这个大黑蒙版,俺是越看越顺眼,越看越觉得这不就是最适合的大画板嘛😆。有了这么大的发挥空间,不得狠狠发挥一下平时无处可使的艺术创想😎。
艺术创想
- 既然解决了画板的问题,那剩下的就是该咋装修了。毕竟初衷是为了加强和网站名之间的关联性,所以题材肯定得是和星星相关的内容。而又是大画板,又是星星,那其实答案已经很明显了。直接整个星空背景,替换原来的大黑蒙版岂不是很酷😎!
- 这就不得不提之前做的几个小游戏,都还属于是即兴发挥状态,做着做着艺术创想就消耗殆尽了,就慢慢得挤不动牙膏了🤡。不过刚刚好这次的主题,非常适合《秘密花园》的那种风格。如果有小伙伴还没看过的话,可以点击这里跳转。而且其实说实话,之前做这个就是用来当背景的,只不过现在那个小作文因为一些原因被我干掉了,所以就改到放在小游戏入口了。嘛,要是感兴趣的话,有时间再单独聊聊这俩小游戏
(企图挖坑不填🤪)。 - 不过毕竟这次是星空主题,所以直接用之前的素材还是不太行。而且说实话,之前整《秘密花园》的时候,那个素材量,对我这种缺乏艺术细菌的人来说,没差点给我脑子整宕机已经谢天谢地了🤪。所以要再来一遍,多少是有点地狱级别了,所以还是不走老路了🙈。
- 而且这次星空的主题,本身对素材的要求其实并不高。所以完全可以不依赖素材,直接用自定义shader的方式,程序化生成所有的内容。这样既能省下绘制素材的精力,又能节省下资源占据的包体大小。毕竟是在主页上用的,资源太大多少还是会影响加载速度💩。
大致实现
- 首先既然是星空,那肯定得先有一个渐变色的夜色作为背景。这部分实现起来最为简单,直接通过uv的纵坐标,将两种颜色通过mix函数进行混合,即可实现渐变色。具体代码差不多就是这么个感觉:
const vec3 blue = vec3(0.13, 0.17, 0.28); const vec3 dark = vec3(0.02, 0.03, 0.08); float ratio = uv.y / drawAreaRect.y + uv.x / drawAreaRect.x * 0.6; //增加uv的横坐标,主要是为了制造一下纵深感 mix(dark, blue, ratio) - 但光是有了夜色肯定还不行,毕竟有星星的天空才是星空嘛(废话文学经验+1🙈)。所以还需要通过算法,实现一下星星的随机分布。这里其实试过很多方式,其中最简单的方式,就是通过屏幕尺寸进行随机分布计算,生成若干个坐标点,然后通过遍历依次逐个绘制。但是这个实现方式虽然简单,就是不太适合用在glsl。毕竟大量的循环,性能压力多少还是有点大。而且毕竟咱们是要做背景的,屏幕尺寸多大都不好说。所以一个星星数量有限的星空,多少还是有点不够意思🤔。
- 所以后来又换了一个方式,毕竟要想适配各种尺寸的大屏幕,首先肯定就是不能通过循环实现。毕竟只要用了循环,就注定了一定是固定数量。那要想数量不限,最简单的方式还是用随机生成噪波。即根据屏幕上的每个uv坐标,经过一个固定的噪波计算,得到这个位置的数值。同时同一个坐标,只要多进行几次偏移计算,最后叠加在一起的数值大小,即可用来模拟当前位置星星的亮度。因此可以完美实现,无论是哪种尺寸的屏幕,都能正常绘制满屏幕的星星。
- 至于具体的噪波算法,这里试了几种,最后使用的还是perlin噪声,因为之前在《秘密花园》里面也用过类似的,所以这次简单改吧改吧就可以复用了,岂不美哉😜。但毕竟这次是用在主页上的,而之前那个版本多少还是有点性能上问题,所以最后还是改成使用Inigo Quilez大佬的版本。性能自不必说,光就这优化后代码的整洁度,就已经足够成为使用的理由了,一起欣赏一下✨!
vec3 hash( vec3 p ) // replace this by something better { p = vec3( dot(p,vec3(127.1,311.7, 74.7)), dot(p,vec3(269.5,183.3,246.1)), dot(p,vec3(113.5,271.9,124.6))); return -1.0 + 2.0*fract(sin(p)*43758.5453123); } float noise( in vec3 p ) { vec3 i = floor( p ); vec3 f = fract( p ); #if INTERPOLANT==1 // quintic interpolant vec3 u = f*f*f*(f*(f*6.0-15.0)+10.0); #else // cubic interpolant vec3 u = f*f*(3.0-2.0*f); #endif return mix( mix( mix( dot( hash( i + vec3(0.0,0.0,0.0) ), f - vec3(0.0,0.0,0.0) ), dot( hash( i + vec3(1.0,0.0,0.0) ), f - vec3(1.0,0.0,0.0) ), u.x), mix( dot( hash( i + vec3(0.0,1.0,0.0) ), f - vec3(0.0,1.0,0.0) ), dot( hash( i + vec3(1.0,1.0,0.0) ), f - vec3(1.0,1.0,0.0) ), u.x), u.y), mix( mix( dot( hash( i + vec3(0.0,0.0,1.0) ), f - vec3(0.0,0.0,1.0) ), dot( hash( i + vec3(1.0,0.0,1.0) ), f - vec3(1.0,0.0,1.0) ), u.x), mix( dot( hash( i + vec3(0.0,1.0,1.0) ), f - vec3(0.0,1.0,1.0) ), dot( hash( i + vec3(1.0,1.0,1.0) ), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z ); } - 当然最后渲染出来的效果,肯定也得展示一下啦🌟~
- 不过光是实现了星空的背景,多少还是有点空洞。所以后来又琢磨着,既然都有星空了,那再加个流星上去,岂不是更酷了🌠。而且弹幕本身也可以类比作流星,所有发过的弹幕,最终都能化作流星,留下美好的印记。也算是给俺的小网站,增加了一些诗意和内涵了✨。
- 具体的实现也算简单,毕竟五角星作为一种基础图形,也已经有非常成熟的生成算法,咱们直接套用一下即可。我这里使用的还是Inigo Quilez的算法,如果大伙对具体原理感兴趣的话,可以直接看Inigo Quilez写的关于多边形的距离函数文章,里面的内容可以说是非常的淋漓尽致了。我使用的算法具体如下:
// signed distance to a 5-star float sdStar(in vec2 p, in float r, in float rf) { const vec2 k1 = vec2(0.809016994375, -0.587785252292); const vec2 k2 = vec2(-k1.x,k1.y); // repeat domain 5x p.x = abs(p.x); p -= 2.0*max(dot(k1,p),0.0)*k1; p -= 2.0*max(dot(k2,p),0.0)*k2; p.x = abs(p.x); // draw triangle p.y -= r; vec2 ba = rf*vec2(-k1.y,k1.x) - vec2(0,1); float h = clamp( dot(p,ba)/dot(ba,ba), 0.0, r ); return length(p-ba*h) * sign(p.y*ba.x-p.x*ba.y); } - 有了五角星之后,剩下的就是通过时间系数,对坐标进行偏移计算。同时为了模拟纵深感,还额外加上了旋转、缩放和缓动函数。最后再用不同的颜色进行多次回溯绘制,即可模拟实现拖尾效果。让咱们看看最终的实现效果:
- 剩下的就是导入到网站上了,这个在做前两个小游戏的时候,就已经把基本框架搭建完了,所以现在再整一遍,就犹如哆啦A梦掏道具——手到擒来了✌️。现在大伙只要点击屏幕右上角的弹幕入口,即可看到最终的渲染效果啦🎉🌠!为了防止有些小伙伴不认识入口在哪,所以这里再把之前的截图拉出来示意一下,不可以再迷路咯😘。

- 不过还是有一些遗憾的地方,因为资源大小问题,虽然不至于影响正常阅读,但要看到效果还是需要等待下载完成。所以网络不理想的情况下,难免还是会比较吃力。不过好在一次下载后就能缓存到本地,不用每次都重新下载,要苦也就苦一次了💩。
- 其次还有一个更头大的问题,就是经过多次测试,感觉移动设备上的帧率,多少还是有些不太理想。尤其是在打开界面的时候,可以明显感受到卡顿。所以无奈之下,只能暂时先在移动设备上关闭显示。嘛,等以后移动设备性能更优秀一点了,再看看要不要打开吧😆。