如何用代码实现一个黑洞效果?| 技术头条


作者 |?叶斋
本文来源于阿里巴巴前端技术专家叶斋在内网的「如何实现某些动画」的系列分享,该系列分享包括如何用代码实现爆炸、黑洞、蜘蛛、扫描等,阿里巴巴中间件受权发布。
因为对动画比较了解的缘故,团队的其他同学时常会找我讨论「如何实现某些动画」,在与同学们的交流过程中,我发现,对大部分前端工程师而言,编写前端动画的难度并不在前端技术本身,而是对动画背后的规律缺乏理解,在尝试用数学语言表达动画时感到困难。
所以,在入门动画的过程中,往往出现这样的情况:即虽然对动画相关的?API?了如指掌,但是一旦遇到实际问题,就显得缺乏思路,无从下手。
其实,掌握动画规律并不困难,甚至可以说是极为简单。而实现各种各样的粒子系统,是一种很好的锻炼动画思路的实践。为此,我尝试推出一个的博文系列「每日一则粒子效果」,每篇文章分析一个简单的小例子,希望能够帮助到大家。
这一篇,我们来看看如何用代码实现一个黑洞效果。

黑洞效果:其实就是粒子一边旋转一边靠近(被吸过去)中心点。在这个粒子中,我们使用极坐标(theta,?r)来代替直角坐标(x,y)描述一个点的位置。

坐标用来描述点,其含义是,唯一的坐标可以确定唯一的点。在直角坐标中,根据(x,y)两个坐标值就可以(无需其他任何信息)确定该点的位置,而在极坐标下,同样根据(theta,?r)两个坐标值,也可以(无需其他任何信息)确定该点的位置。极坐标和直角坐标之间可以进行转化,如图所示:x?=?r?*?cos(theta),y?=?r?*?sin(theta)。
这个模型中需要注意的是:在直觉上,黑洞效果的一个显著特点,就是粒子被吸入进去的时候,其速度是越来越快的,当粒子比较接近黑洞中心的时候,粒子是以非常快的速度旋转和逼近黑洞中心,然后消失。这其实与我们所学习的能量守恒定律有类似之处,当粒子越来越靠近黑洞,其旋转半径越来越小,势能就转化为了动能,所以粒子的线速度就越来越快。利用这「近似的能量守恒」,就可以制作出比较逼真的黑洞效果了。
在初始化的时候,为每个粒子生成随机的极坐标?theta?和?radius,然后生成限定在特定区间内的随机速度。
这里需要注意的是,radius?和?speed?需要在特定区间内,才能有比较好的效果,如果粒子的速度过快或半径过大,在真实环境下是可能逃离黑洞的,制作动画时强行使其被吸入黑洞,会使动画的效果打折。
points.push({
??...
??theta:?Math.random()?*?Math.PI?*?2,
??radius:?RADIUS?*?(Math.random()?*?0.5?+?0.1),
??speed:?SPEED?*?(Math.random()?*?0.6?+?0.2)
})
每一帧粒子位置的逻辑如下:
var?theta?=?p.theta;
var?radius?=?p.radius;
var?speed?=?p.speed;
var?dTheta?=?speed?*?step?/?radius;
var?dRadius?=?(8000?/?(radius?*?radius)?-?speed?*?speed)?*?step?/?10;
var?dSpeed?=?Math.sqrt(dRadius)?/?500;
p.theta?+=?dTheta;
p.radius?-=?dRadius;
p.speed?+=?dSpeed;
极坐标角度值?theta??的增量,即旋转过的角度,是粒子的速度乘以时间除以半径得到。
极坐标半径值?radius?的增量,与引力和离心力的差有关。引力与半径的平方成反比,离心力与速度的平方有关系。
粒子速度的增量与半径增量的开方成正比。
上述模型也只是真实世界的粗糙模拟,比如第二条,引力与离心力的差其实影响的是坠落的加速度,我们简单地使之与速度正相关;又比如第三条中速度增量与半径增量开放成正比,其实只适用于引力不变的情况,这时候就不得不配合一些「神奇数」调试出合适的效果。
反复调试代码中的一些常量,直到效果满足我们的预期。
源代码地址:
https://xieguanglei.github.io/particles-day-by-day/pages/day4-better-blackhole/index.js
作者:谢光磊(花名:叶斋),阿里巴巴前端技术专家,专注于前端图形渲染领域的架构和开发工作。《WebGL?编程指南》译者,开源?WebGL?3D?引擎?G3D?核心开发者。
声明:本文为公众号阿里巴巴中间件投稿,版权归其所有。
【End】

?热 文?推 荐?
戳他↓↓↓
?掌握?Android?系统架构,看这一篇就够了!|?技术头条
?39个国外SCI抢发6万篇中国英文论文?然而,真正的问题是……
System.out.println("点个在看吧!");
console.log("点个在看吧!");
print("点个在看吧!");
printf("点个在看吧!n");
cout?< "点个在看吧!"?< Console.WriteLine("点个在看吧!");
Response.Write("点个在看吧!");
alert("点个在看吧!")
echo "点个在看吧!"
点击阅读原文,输入关键词,即可搜索您想要的?CSDN?文章。

关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
关注网络尖刀微信公众号随时掌握互联网精彩
- 1 习近平将发表二〇二六年新年贺词 7904141
- 2 2026年国补政策来了 7808738
- 3 东部战区:开火!开火!全部命中! 7712893
- 4 2026年这些民生政策将惠及百姓 7616985
- 5 小学食堂米线过期2.5小时被罚5万 7519709
- 6 解放军喊话驱离台军 原声曝光 7428214
- 7 为博流量直播踩烈士陵墓?绝不姑息 7327605
- 8 每月最高800元!多地发放养老消费券 7238391
- 9 数字人民币升级 1月1日起将计付利息 7141831
- 10 2026年1月1日起 一批新规将施行 7040675








CSDN
