假如在生活中看到很清澈的水面上的水波纹,是不是会觉得很美呢?
可是你想过用算法来模拟这样的画面吗?
实现水波纹的基原理如下:
说到波,学过物理的都知道,可以用sin或cos来模拟波,水波纹亦是如此。不同的是,在现实中随着传播的距离的增加,水波的能量衰减的很快,而不是我们所学的一直以不变的振幅传播下去。
方法如下:
- 以图片的中心为水波的中心,取宽高的较大值的一半做水波纹的直径
- 波能的扩散/衰减
- 渲染效果
//水波纹 public static Bitmap WaterWave(Bitmap bitmap){ int w = bitmap.getWidth(); int h = bitmap.getHeight(); int[] buf1 = new int[w * h]; int[] buf2 = new int[w * h]; int[] source = new int[w * h]; Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565); bitmap.getPixels(source, 0, w, 0, 0, w, h); int[] temp = new int[source.length]; int x = w / 2; int y = h / 2; int stonesize = Math.max(w, h) / 4; int stoneweight = Math.max(w, h); if ((x + stonesize) > w || (y + stonesize) > h || (x - stonesize) < 0 || (y - stonesize) < 0){ return null; } for (int posx = x - stonesize; posx < x + stonesize; posx++){ for (int posy = y - stonesize; posy < y + stonesize; posy++){ if ((posx - x) * (posx - x) + (posy - y) * (posy - y) <= stonesize * stonesize){ buf1[w * posy + posx] = (int)-stoneweight; } } } for(int i = 0 ; i < 170; i++){ for (int j = w; j < w * h - w; j++){ //波能扩散 buf2[j] =(int)(((buf1[j-1]+buf1[j+1]+buf1[j-w]+buf1[j+w])>>1)- buf2[j]); //波能衰减 buf2[j] -= buf2[j]>>5; } //交换波能数据缓冲区 int[] tmp =buf1; buf1 = buf2; buf2 = tmp; /* 渲染水纹效果 */ int xoff, yoff; int k = w; for (int m = 1; m < h - 1; m++) { for (int j = 0; j < w; j++) { //计算偏移量 xoff = buf1[k-1]-buf1[k+1]; yoff = buf1[k-w]-buf1[k+w]; //判断坐标是否在窗口范围内 if ((m+yoff )< 0 || (m+yoff )>= h || (j+xoff )< 0 || (j+xoff )>= w) { k++; continue; } //计算出偏移象素和原始象素的内存地址偏移量 int pos1, pos2; pos1=w * (m + yoff) + (j + xoff); pos2=w * m + j; temp[pos2++]=source[pos1++]; k++; } } } result.setPixels(temp, 0, w, 0, 0, w, h); return result; }
效果如下:
原图如下:
效果还是有待改善。
这里是效果比较好的博文链接:链接
作者:qq_32353771 发表于2016/11/30 21:05:43 原文链接
阅读:42 评论:0 查看评论