最近看到一个炫酷的放烟花效果:

3D放烟花效果 gif 3D放烟花效果

源码也并不是那么容易看懂,下面记录了一些源码中的难点:

粒子范围

主要是源码中的rasterizePoint方法:

这个方法比较难理解,它的作用主要是将3D坐标展现在2D上,我们先看它的下半部分,就是从var rx1 = -1000,往后的代码,看看那个计算表达式是计算啥的,到底有啥作用?

首先我们将等式中的ua,ub简化一下:

ua>0&&ua<1,(线条的斜率都是K43),想表达的内容是第四个点(D),需要在CA,CB的射线范围内,我们先看个正常范围的:

background Layer 1 x z B(x2,y2) A(x1,y1) C(x3,y3) D(x4,y4) b1 b3 b2 b1 - b3 b1 - b2 0 < < 1

很明显可以看到(b1-b3)/(b1-b2)的范围是在[0,1]之间的。我们看看如果D超过了射线范围:

background Layer 1 x z B(x2,y2) A(x1,y1) C(x3,y3) D(x4,y4) b1 - b3 b1 - b2 >1 b3 b2 b1

我们可以看到如果D不在范围之内,那么ua将>1。

ub>0&&ub<1,(线条的斜率都是K12),想表达的内容是第四个点(D),需要在AB射线之上,我们先看个正常范围的:

background Layer 1 x z B(x2,y2) A(x1,y1) C(x3,y3) D(x4,y4) b1 - b3 b4 - b2 <1 b3 b4 b1 0<

我们看个在AB射线之下的:

background Layer 1 x z B(x2,y2) A(x1,y1) C(x3,y3) D(x4,y4) b1 - b3 b4 - b2 >1 b3 b4 b1

因此我们可以知道,ua>0&&ua<1,ub>0&&ub<1,是要让点的范围在指定范围,范围如下:

background Layer 1 x z C(x3,y3)

转换后的坐标:rx1 + ua * (rx2 - rx1)则是根据ua的比例,将点展现在[rx1,rx2]这个范围内;其实我们可以理解成范围内的点都会投影到AB这个平面上(xz坐标是俯视图,实际上AB是一个平面)。

player和yaw,pitch,roll

这个是出现在rasterizePoint上半部分的内容,player代表一个观察者,具体有playerX,playerY,playerZ,代表这个观察者的三维坐标。

yaw,pitch,roll是从航天飞机那边来的概念: yaw,pitch,roll,简单来说,yaw代表绕着y轴旋转;pitch代表绕着x轴旋转;roll代表绕着z轴旋转。

我们看一下player配合yaw如何实现绕y轴旋转(方块代表生成的粒子范围,它的范围类似一个长方体,通过位移旋转得到最终投影结果):

background Layer 1 x z 观察者 x z 观察者 将观察者移到中心 x z 观察者 yaw旋转到正视的位置 投影 投影

第一步将观察者放到中心位置,第二步将点旋转一个角度,这样旋转后的投影刚好就为三维物体的侧面。

那么到底旋转多少度才能呢?代码中为p-yaw度(其中yaw=pi+a,yaw角度在doLogic方法中赋值):

background Layer 1 x z 观察者 x z 观察者 将观察者移到中心 yaw旋转到正视的位置 a a x z 观察者 a a p

p = Math.atan2(x, z);它求的是对边/邻边对应的角度,也就是上图中的a,p。其中a为旋转前得到的结果(记录yaw=a+pi),通过第一步将粒子范围位移后,再次计算得到角度p,然后p-yaw就可以得到粒子范围的侧面投影。

绘制3D球星烟花

splode方法中有一段代码比较难懂,它的作用是用来绘制3D球:

先随机得到到一个三维速度V,然后将它在xy轴上分解,得到Vy和Vxz,然后将Vxz在x和z轴分解,分解后的点其实在分布在一个3D球上:

background Layer 1 x y V Vy Vxz a a的范围[0,pi],半圆 x z Vxz Vx Vz b b的范围[0,2*pi]

其中第一个角度的范围在[0,pi],第二个角度的范围在[0,2*pi],直观的展示如下:

background Layer 1

烟花尾巴效果

在播放烟花的时候,我们不断的放入烟花尾巴:

我们可以看到,烟花尾巴其实就是烟花经过的点,尾巴数组最多可以保留5个,并且只有当尾巴之间的距离达到一定距离的时候才会保存。

现在我们来看看绘制烟花尾巴:

烟花尾巴绘制的整体逻辑是将尾巴数组中的点利用moveTo,lineTo连接起来,其中globalAlpha想表达越靠近后面的尾巴透明度越小。

lineWidth中为啥要除以(1 + point2.d)?为的是实现线条粗细的3D效果,距离越远的尾巴,越细。(同时为了方式point.d为0,因此+1),这种除以(1+d)的在很多地方都有,都是为了实现大小,尺寸等的3D效果,远小近大。

其他文章

0
我要评论

评论

返回
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

提交
还可以输入500个字