【Aegisub】火焰模拟、火焰仿真效果

前面介绍了融球效果,提到了利用液滴也可以做出火焰效果:

当然也说了,利用噪声同样可以做火焰仿真效果:


当然之前也反复说过,这些效果都不是用一堆像素做的,而是直接生成一块块大的绘图来做的。
那么现在,就来讲讲这两种火焰是怎么做的。首先讲第二种是怎么做的。
之前讲了分形噪声能做下图的效果

但问题是一整张噪声图,怎么变成类似三角形的样子。那就要用到纹理映射(或者说纹理贴图),现在只需要简单地用到其中的思维即可。现在假设噪声图是这样的

假设黑色是0、白色是1、灰色当然是0到1之前,每一个点都对应一个噪声值。现在要得到火焰说明要过滤掉一些部分,所以可以做标记(即mask),使每一个点对应的值发生改变,最后只留下数值在规定范围的点即可。比如可以让下面三角形部分的点对应的数值更大、其它部分的点对应的数值更小,这样就可以过滤不需要的部分了。
举例子比如,现在准备这样一张图:

黑色到白色就是0到1、图中每个点对应一个0到1的数值,那每个点的数怎么算呢,显然越接近底部数字越大,所以用纵坐标的差距即可。假设顶部y是0、底部y是h,那么任意一点到底部的距离是math.abs(h-y),将其变到0到1之间是math.abs(h-y)/h,而math.abs(h-y)/h当然是越接近底部的点数值越小、在底部的点数值就是math.abs(h-h)/h=0,但是现在想要从顶部到底部的点对应的数值是从0到1、而不是从1到0,所以反过来就行了,这很简单,用"1-"即可。也就是1-math.abs(h-y)/h不就行了吗,1-math.abs(h-y)/h就是从0到1了。那么不就可以利用这张图来标记噪声图的点吗、将这张图作为mask。将两张图相加就有

两张图的数的范围反正可以随便设定嘛,既然现在两张图各点的数值都是0到1,那加起来就变成了0到2,可以除以2嘛。

可以看到,原本的噪声图(左)加了mask标记以后就得到了右图了。这样每个点对应的数值就变了嘛,然后你就可以保留数比较大的点了,比如如果某点对应的数值大于0.61,那么就保留这一点,于是就有

当然全部画为白色就有

再比如,现在保留所有数值大于0.27的点,那么就有

那么现在已经有了火焰的形状了,然后你就可以让它动起来的不是吗?只需要平移噪声图即可,之前其实已经讲过的嘛。要让火焰往上飘,只需要让噪声图往下移动即可,也就是增加y,随着时间的增加,噪声图里每个点的y坐标在原本的基础上一点点增大,然后每一帧得到的图连起来即可。这样不就可以做出这样的效果了吗:

所以现在只需要mask是三角形的即可。这也很简单,只需要两张图就能得到想要的mask

刚刚已经讲了、用了右边的纹理图,现在只需多计算一张新的图、即左边的图,将左右两个图加起来(或者相乘也行)不就可以得到三角形的mask了吗:

当然相乘也可以得到三角形的mask,还是一样的道理

然后刚刚已经讲了下图的右边的图是怎么做的,然后现在还需要得到左边的图

左边的图很容易得到,横向看每个点代表的数值是从0到1再到0的,什么意思,也就是说,点离中间越近则该点对应的数字越接近1。假设横坐标从0开始到w结束,则中间的x是w/2,所以任意一点到中间线的距离是math.abs(w/2-x),然后产生1到0的过渡即math.abs(w/2-x)/(w/2),由于需要的是0到1到0而不是1到0到1,所以同样的,反过来,用上"一减"、即"1-",就有1-math.abs(w/2-x)/(w/2)了,这样不就有了从0到1到0的变化了吗,也就是

这样两个图相加,就有了三角形mask了

这样就又可以对噪声图作标记了:

显然,作标记以后、有了可爱的mask以后,每个点代表的数值就又变化了,这样又可以过滤掉一部分数值的点,比如现在只保留大于0.53的点,那么就有

这不就出来了吗?其它细节你可以自己调嘛。现在比如你又设定只保留大于0.7的点,那么范围当然就更小了:

这样通过范围的设定,就能画出不同的等值线、做出内焰和外焰的效果了:

显然,做火焰效果是不需要用一堆像素做的,因为早就讲过了,如何绘制等值线,所以只需要绘制出一整块的、大的绘图即可。当然绘制的网格和生成噪声图的网格不是一回事、没理由把它们搞混。那么这样第二种火焰效果的原理和实现就介绍清楚了。所以当然你可以有各种各样的mask来做各种各样的效果,可谓千变万化。
再反复讲一下,刚刚的渐变图,每一个点都对应一个0到1的数字,而为了将其可视化,就配上了颜色、黑色是0白色是1,这样就有"渐变图"了。然后两张图相加就是字面意思的相加,每个点对应的数字相加即可得到新的数字、然后你可以将这个数字的范围重新控制在0到1之间。同样,两个图相乘也是一样的,每个点对应的数字相乘即可,当然0到1的数字乘以0到1的数字得到的数字结果还在0到1这个范围内,很方便。实际上,图和图加减乘除都不奇怪,而且根据需要,有时也会把一个图平方,比如下图原本是这样的:

平方以后就变成了

显然对于一个0到1的数,平方以后数字就会比原本的更小,所以现在的图接近白色的部分就更少了。
然后关于mask,一般是翻译成遮罩,但显然mask和clip并不是一回事,虽然clip也可翻译成遮罩,不过,clip翻译成裁剪会更加"精准"一些。其实在图形布尔运算里,clip就是翻译成裁剪的。所以如果以后我提到mask遮罩时,一定不要理解成clip了。
然后就是介绍第一种火焰效果怎么做。当然是用融球做的,也非常的简单。只需要不停地向上发射小球、然后对这些小球做融合效果即可。

很简单,先设置一个大的球,然后每一帧发射一些小球(比如每帧发射两个新的小球),小球的半径当然需要比大球小很多很多了。小球可以从大球中心的位置开始发射出来,也可以在其它位置开始发射,比如离大球顶部近一些的位置。然后你还可以每一帧让已经发射出的小球慢慢变小,如果小球半径小到一定程度或者小球已经移动到绘制画布外,就可以将物体表里的该小球删除。这样,对每一帧的这些物体(球)做融合效果即可。非常简单就有了融球火焰效果了。