这里我将陆续发布一些我自己做的小程序,有些程序可能有点粗糙,希望各位高人多加指点!首先把我今年3月份作的一个程序,拿来晾一下。本程序实现对水波折射等物理现象的模拟。
水波纹屏保
程序效果图:
水波是我们生活中非常常见的现象,在阳光下反射出亦幻亦真的奇妙光线的舞蹈。不知你是否曾几何时被其所迷倒过呢。
水波的这种奇幻效果是非常适合做屏保的。于是我就想到可以做一个水波纹屏保。到网上查询一下,发现已经有人做出类似的屏保了,不禁有些失望。
无聊之下,下载了他的程序,玩味之中,我发现他的程序的波纹只是遵照固定的模式运行,并没能将水波的万千变化融会其中。仔细分析之后,可以看到他的波纹只是多个环相套的结果,没有根据水面的物理性质进行实时状态的计算,使得水波的姿态非常呆板,而且不够细腻。
水波模型
制作水波的模拟程序,首先要建立一个水波的演化模型。实际的水是一个具有体积的实体,有厚度,但是学过中学物理的都知道,水对光的折射与反射,主要取决于水面的形态。所以我们如果要建立一个关于水的模型,一个矩阵就可以近似表示了。
那么这个矩阵中每一个点应该记录什么呢?水面是一个个的水分子组成的,在水分子之间存在着非常复杂的力,在这些力的作用下,水分子也随着运动。查阅书籍你可以发现,实际上在一个波通过的时候,水面上的一个水分子近似作如下运动:
这个运动比较复杂,我们可以将它简化,认为它只是做上下运动:
该简化的结果实际是只考虑水分子之间的粘滞力,而忽略了水分子的互相推拉,从而使其没有水平位移。那么这样做是否能够近似的模拟水面的波动效果呢?实践是检验真理的唯一标准,做一个简单的程序试试吧!运用该原理制作的水面效果如图:
可以看到这样的近似对于水波的模拟还是能够起到比较好的效果,不至于有过大的失真。在这个小程序中矩阵中的点记录的是水面在特定位置的高度以及该点的运动速度。水分子的作用力只影响它周围上、下、左、右四个分子,根据它们的高度差计算出互相的拉力,并计算出这个水分子所受的合力,作为这个水分子的加速度,以影响水分子在下一时刻的速度,同时根据水分子的速度计算出该水分子在下一时刻的高度。
水面的折射与反射
现在我们的程序设计已经完成了一半,可以看到一个失真度可以容忍的水面模型已经被建立起来了。我们已经得到了水面在各个时刻的高度,剩下的任务就简单了。我们最终的目的是需要得到图像被水面折射后的画面,那么水面是如何折射光线的呢?这个根据中学的知识我们就可以知道:
产生的效果就是在水面下的图像由于水的波动而产生了视觉位移,经过试验以两个点之间的高度差作为这个位移量是合适的。
至于水面的反射。其实当我们从上面俯视水面时,在一般情况下的反射现象要小于折射现象,这是因为反射现象只有在超过某个临界值是才会出现全反射。程序中体现为视觉位移足够大,而这时最有可能的情况是已经超出了图像的边界,所以我的程序中在超出图像时将颜色定为白色,看上去就像水面产生了耀眼反射。
程序的编写
关于屏保程序的编写,微软的MFC有一套特定的模版,网上也有许多教程,我这里就不再缀述了。
首先,我们屏保是对当前的桌面进行图像扭曲,所以我们需要截取当前屏幕的图像,这个比较简单,先取得桌面的设备上下文(::GetDC(NULL)),然后再用一个位图将图像保存下来。
接下来,需要对图像进行扭曲,刚开始,我只是根据模型逐点进行图像填充,发现速度实在太慢,我的机子配置是P3.0G-512M都受不了。后来我对图像进行了三角形填充。
下面讨论这种特殊的三角形贴图公式。
公式:将直角三角形A上的点p0(x0, y0)映射到一个任意三角形B上的点p1(x1, y1)
x1 = a0 + (a1 – a0) * x0 / W+ (a2 – a0) * y0 / H
y1 = b0 + (b1 – b0) * x0 / W + (b2 – b0) * y0 / H
其中W和H为直角三角形的宽和高,(a0 ,b0)(a1 ,b1)(a2 ,b2)为B的三个顶角坐标,A与B的对应关系如图所示
具体应用到贴图时,4个乘除法运算可以转化为一次乘除法运算 + 多次加法运算,以提高运算速度。
贴图算法贴图的效果如下:
现在的运算速度已经基本可以满足一般机器的运算能力了。当然,在比较差的机子上还是会显得比较吃力。为什么网上的程序可以做到比较快的运算速度呢?这是因为他调用了Direct的三角型贴图,而且三角形个数很少,相比之下我是用自己实现的算法,三角形个数也比他多了不止一个数量级别。不过C语言与汇编语言的速度差别也在此体现的很明显。
下载链接:
地址: http://simplesource.blog.163.com/blog/static/10341406200662585620/