这是效果图注意荷叶边的效果。
经典的水波算法:
//能量的扩散
t=waterB[a-mWidth];
b=waterB[a+mWidth];
r=waterB[a+1];
l=waterB[a-1];
waterA[a]=((t+b+l+r)>>1)-waterA[a];
//能量的衰减
waterA[a]-=(waterA[a]>>6);
一个非常重要的依据--能量守恒。
在无阻尼前提下,一个时间内的所有水分子的能量之和是不变的
上面的能量的扩散就是按照这个原则实现的,感兴趣的话看一下
http://tech.163.com/05/0624/10/1N0LUJM600091589.html
http://www.chinaitpower.com/A/2001-12-20/8376.html
这里就不再重复了。
waterA,waterB是两个int 数组,用来保存和推演波的能量。
什么样的波会反射?
简单的来说我打了老婆十下,老婆也打了我十下这样就相当与有十下被反射回来了。
当一个水分子给左边的水分子的能量被原样返回时便使得水波想右反射了。
当我们计算waterB到A的变换(也就是上一个时间点和下一个时间点的波的变换)时,如果该点的波的能量被忽略过去时,该点会保留原来的能量,并把它保存到了下一个时间段,然后把自身的能量想周围扩散。
下面是关键部分的代码:
for(int a=mWidth;a<mArrayLen-mWidth;a++)
{
//边缘反射
if(a%mWidth==0)
continue;
//根据障碍物计算波的反射
if(this->mBarrier!=NULL&&this->mBarrier[a*mBarrierBytesPerPix]!=0)
continue;
int t,b,l,r;
//能量的扩散
t=waterB[a-mWidth];
b=waterB[a+mWidth];
r=waterB[a+1];
l=waterB[a-1];
waterA[a]=((t+b+l+r)>>1)-waterA[a];
//能量的衰减
if(m_decayFactor>0)
waterA[a]-=(waterA[a]>>m_decayFactor);
}
COLOR_INT *temp=waterA;
waterA=waterB;
waterB=temp;
int xoff,yoff;
for(int u=1;u<mWidth-1;u++)
{
for(int v=1;v<mHeight-1;v++)
{
//判断坐标是否在窗口范围内
xoff=waterA[u-1+v*mWidth]-waterA[u+1+v*mWidth];
yoff=waterA[u+(v-1)*mWidth]-waterA[u+1+(v+1)*mWidth];
if ((v+yoff )< 0 ) {continue;}
if ((v+yoff )>mHeight) {continue;}
if ((u+xoff )< 0 ) {continue;}
if ((u+xoff )>mWidth ) {continue;}
//计算出偏移象素和原始象素的内存地址偏移量
int Color;
int BackIndex=(u+xoff+(v+yoff)*mWidth)*mBarrierBytesPerPix;
if(this->mBarrier!=NULL&&this->mBarrier[BackIndex]!=0){
Color=(mBarrier[BackIndex]);
for(int i=1;i<mBarrierBytesPerPix;i++)
Color+=mBarrier[BackIndex+i]<<(8*i);
}
else
{
Color=(mBackImage[BackIndex]);
for(int i=1;i<mBackImageBytesPerPix;i++)
Color+=mBackImage[BackIndex+i]<<(8*i);
}
//result[u+mWidth*v]=RGB(yoff,xoff,0);
result[u+mWidth*v]=Color;
}
}
mBackImage:
mBarrier: