Ripple[水波]程序实现水波效果水纹特效算法

上传人:飞*** 文档编号:51023758 上传时间:2018-08-12 格式:PDF 页数:5 大小:53.40KB
返回 下载 相关 举报
Ripple[水波]程序实现水波效果水纹特效算法_第1页
第1页 / 共5页
Ripple[水波]程序实现水波效果水纹特效算法_第2页
第2页 / 共5页
Ripple[水波]程序实现水波效果水纹特效算法_第3页
第3页 / 共5页
Ripple[水波]程序实现水波效果水纹特效算法_第4页
第4页 / 共5页
Ripple[水波]程序实现水波效果水纹特效算法_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《Ripple[水波]程序实现水波效果水纹特效算法》由会员分享,可在线阅读,更多相关《Ripple[水波]程序实现水波效果水纹特效算法(5页珍藏版)》请在金锄头文库上搜索。

1、看到左边这幅动画(如果没有出现,请耐心的稍等片刻),你也许不会相信它其实是用电脑做出来的,这就是“ 水波 ” 特效的魅力所在。在介绍编程之前,先让我们来回顾一下在高中的物理课上我们所学的关于水波的知识。水波有如下几个特性:扩散 :当你投一块石头到水中,你会看到一个以石头入水点为圆心所形成的一圈圈的水波,这里,你可能会被这个现象所误导,以为水波上的每一点都是以石头入水点为中心向外扩散的,这是错误的。实际上,水波上的任何一点在任何时候都是以自己为圆心向四周扩散 的,之所以会形成一个环状的水波,是因为水波的内部因为扩散的对称而相互抵消了。衰减 :因为水是有阻尼的,否则,当你在水池中投入石头,水波就会

2、永不停止的震荡下去。水的折射 :因为水波上不同地点的倾斜角度不同,所以,因为水的折射,我们从观察点垂直往下看到的水底并不是在观察点的正下方,而有一定的偏移。如果不考虑水面上部的光线反射,这就是我们能感觉到水波形状的原因。反射 :水波遇到障碍物会反射。衍射 :忽然又想到这一点,但是在程序里却看不到,如果能在水池中央放上一块礁石,或放一个中间有缝的隔板,那么就能看到水波的衍射现象了。好了,有了这几个特性,再运用数学和几何知识,我们就可以模拟出真实的水波了。但是,如果你曾用 3DMax 做过水波的动画,你就会知道要渲染出一幅真实形状的水波画面少说也得好几十秒,而我们现在需要的是实时的渲染,每秒种至少

3、也得渲染20 帧才能使得水波得以平滑的显示。考虑到电脑运算的速度,我们不可能按照正弦函数或精确的公式来构造水波,不能用乘除法,更不能用 sin、cos,只能用一种取近似值的快速算法,尽管这种算法存在一定误差,但是为了满足实时动画的要求,我们不得不这样做。首先我们要建立两个与水池图象一样大小的数组buf1PoolWidth*PoolHeight和buf2PoolWidth*PoolHeight(PoolWidth=水池图象的象素宽度、PoolHeight=水池图象的象素高度) ,用来保存水面上每一个点的前一时刻和后一时刻波幅数据,因为波幅也就代表了波的能量, 所以以后我们称这两个数组为波能缓冲区

4、。水面在初始状态时是一个平面,各点的波幅都为 0,所以,这两个数组的初始值都等于0。下面来推导计算波幅的公式我们假设存在这样一个一次公式,可以在任意时刻根据某一个点周围前、后、左、右四个点以及该点自身的振幅来推算出下一时刻该点的振幅,那么, 我们就有可能用归纳法求出任意时刻这个水面上任意一点的振幅。如左图,你可以看到,某一时刻,X0 点的振幅除了受 X0 点自身振幅的影响外,同时受来自它周围前、后、左、右四个点(X1、X2、X3、X4)的影响(为了简化,我们忽略了其它所有点),而且,这四个点对a0 点的影响力可以说是机会均等的。那么我们可以假设这个一次公式为:X0=a(X1+X2+X3+X4)

5、+bX0 (公式 1)a、b 为待定系数,X0为 0 点下一时刻的振幅X0、 X1、 X2、X3、X4 为当前时刻的振幅下面我们来求解a 和 b。假设水的阻尼为0。在这种理想条件下,水的总势能将保持不变。也就是说在任何时刻,所有点的振幅的和保持不变。那么可以得到下面这个公式:X0+X1+.+Xn = X0+X1+.+Xn 将每一个点都象公式1 那样计算,然后代入上式,得到:(4a+b )X0+ ( 4a+b )X1+. (4a+b )Xn = X0+X1+.+Xn = 4a+b=1找出一个最简解:a = 1/2、b = -1因为 1/2 可以用移位运算符“” 来进行,不用进行乘除法,所以,这组

6、解是最适用的而且是最快的。那么最后得到的公式就是:X0= (X1+X2+X3+X4) / 2- X0好了, 有了上面这个近似公式,你就可以推广到下面这个一般结论:已知某一时刻水面上任意一点的波幅,那么,在下一时刻,任意一点的波幅就等于与该点紧邻的前、后、左、右四点的波幅的和除以2、再减去该点的波幅。应该注意到,水在实际中是存在阻尼的,否则,用上面这个公式,一旦你在水中增加一个波源,水面将永不停止的震荡下去。所以, 还需要对波幅数据进行衰减处理,让每一个点在经过一次计算后,波幅都比理想值按一定的比例降低。这个衰减率经过测试,用1/32 比较合适,也就是1/25 。可以通过移位运算很快的获得。到这

7、里,水波特效制作中最艰难的部分已经度过了,下面是源程序中计算波幅数据的代码。/* / 计算波能数据缓冲区/* void RippleSpread() for (int i=BACKWIDTH; i1) - buf2i; / 波能衰减buf2i -= buf2i5; / 交换波能数据缓冲区short *ptmp =buf1; buf1 = buf2; buf2 = ptmp; 写到这里,我已经两眼发晕了,呼呼,先休息一下 好了,下面再来根据算出的波幅数据对页面进行渲染。因为水的折射, 当水面不与我们的视线相垂直的时候,我们所看到的水下的景物并不是在观察点的正下方,而存在一定的偏移。偏移的程度与水

8、波的斜率,水的折射率和水的深度都有关系,如果要进行精确的计算的话,显然是很不现实的。同样,我们只需要做线形的近似处理就行了。因为水面越倾斜,所看到的水下景物偏移量就越大,所以,我们可以近似的用水面上某点的前后、左右两点的波幅之差来代表所看到水底景物的偏移量。在程序中,用一个页面装载原始的图象,用另外一个页面来进行渲染。先用Lock 函数锁定两个页面,取得指向页面内存区的指针,然后用根据偏移量将原始图象上的每一个象素复制到渲染页面上。进行页面渲染的代码如下:(下面的代码为了便于理解,并没有进行优化,实际上,优化后的代码比它要麻烦许多)/* / 根据波能数据缓冲区对离屏页面进行渲染/* void

9、RenderRipple() / 锁定两个离屏页面DDSURFACEDESC ddsd1, ddsd2; ddsd1.dwSize = sizeof (DDSURFACEDESC); ddsd2.dwSize = sizeof(DDSURFACEDESC); lpDDSPic1-Lock(NULL, lpDDSPic2-Lock(NULL, / 取得页面象素位深度,和页面内存指针int depth=ddsd1.ddpfPixelFormat.dwRGBBitCount/8; BYTE *Bitmap1 = (BYTE*)ddsd1.lpSurface; BYTE *Bitmap2 = (BYT

10、E*)ddsd2.lpSurface; / 下面进行页面渲染int xoff, yoff; int k = BACKWIDTH; for (int i=1; i BACKHEIGHT) k+; continue; if (j+xoff ) BACKWIDTH ) k+; continue; / 计算出偏移象素和原始象素的内存地址偏移量int pos1, pos2; pos1=ddsd1.lPitch*(i+yoff)+ depth*(j+xoff); pos2=ddsd2.lPitch*i+ depth*j; / 复制象素for (int d=0; dUnlock( lpDDSPic2-Unl

11、ock( 增加波源俗话说:无风不起浪,为了形成水波,我们必须在水池中加入波源,你可以想象成向水中投入石头,形成的波源的大小和能量与石头的半径和你扔石头的力量都有关系。知道了这些,那么好,我们只要修改波能数据缓冲区buf ,让它在石头入水的地点来一个负的“ 尖脉冲 ” ,即让bufx,y=-n。经过实验, n 的范围在( 32128 )之间比较合适。控制波源半径也好办,你只要以石头入水中心点为圆心,画一个以石头半径为半径的圆,让这个圆中所有的点都来这么一个负的“ 尖脉冲 ” 就可以了(这里也做了近似处理)。增加波源的代码如下:/* / 增加波源/* void DropStone(int x,/x

12、坐标int y,/y坐标int stonesize,/波源半径int stoneweight)/波源能量 / 判断坐标是否在屏幕范围内if (x+stonesize)BACKWIDTH | (y+stonesize)BACKHEIGHT| (x-stonesize)0| (y-stonesize)0) return; for (int posx=x-stonesize; posxx+stonesize; posx+) for (int posy=y-stonesize; posyy+stonesize; posy+) if (posx-x)*(posx-x) + (posy-y)*(posy-

13、y) stonesize*stonesize) buf1BACKWIDTH*posy+posx = -stoneweight; 好了,至此,水波特效的制作原理就此就全部揭示了。在上面的推导中,每一步都进行了很多看似非常过分的近似处理,但是,你完全不必担心,事实证明,用这种方法,在速度和图象上都可以获得非常好的效果。源程序中有非常详尽的注释,仔细推敲一下,看懂它们应该不成问题。这个程序是Win32 下的 DirectX 编程,没有使用任何包装库。在我的电脑上(AMDK6-200 、2MVRam 、64MSRam ),320x240的画面大小,每秒可以达到25 帧。与前几个程序不一样,这个程序使用了窗口模式,所以调试起来很方便。如果你对窗口模式编程不熟悉,这个程序也是一个很好的例子。这种用数据缓冲区对图象进行水波处理的方法,有个最大的好处就是,程序运算和其示的速度与水波的复杂程度是没有关系的,无论水面是风平浪静还是波涛汹涌,程序的fps 始终保持不变,这一点你研究一下程序就应该可以看出来。实际上, 如果你掌握了这种方法,将这种方法推广一下,完全可以做出另外一些特殊的效果,如烟雾、大气、阳光等,我现在也正在研究这些特效的制作,相信不久以后就会有新的收获。http:/

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号