Principle and Implementation of the android Water Wave Effect

Source: Internet
Author: User

Note:
The algorithm in this article is part of the materials from gameres, the original author imagic. I just thought of this special effect when I was learning Android, and then implemented it on Android. I added the effects of raindrops and ripple effects on the basis of the source algorithm. This program runs slowly on both the simulator and the real machine and needs to be further optimized or implemented using JNI.

Effect:



Basic knowledge:
Before explaining the code, let's review what we learned about water waves in the high school physics class. Water Waves have the following characteristics: diffusion, attenuation, refraction, reflection, diffraction, etc:

Spread: when you drop a rock into the water, you will see a water wave formed by the Circle centered around the stone water point. Here, you may be misled by this phenomenon, it is wrong to think that each point on the water wave spreads outward at the center of the stone water point. In fact, any point on a water wave spreads around at any time with itself as the center of the circle. The reason is that a circular water wave is formed, the reason is that the water waves are offset by the symmetry of the diffusion.
Attenuation: Because water has damping. Otherwise, when you put stones into the pool, water waves will never stop fluctuating.
Refraction: Because the skew angles of different locations on the water waves are different, we can see from the vertical down of the observation point that the bottom of the water is not at the bottom of the observation point, but there is a certain offset. If we do not consider the light reflection on the top of the water surface, this is why we can feel the shape of water waves.
Reflection: water waves are reflected when they encounter obstacles.
Diffraction: place a reef in the center of the pool, or place a middle slit partition, then you can see the Diffraction Phenomenon of water waves.

Algorithm derivation:
Well, with these features, we can use mathematical and geometric knowledge to simulate real water waves. However, if you used 3dmax for water wave animation, you would know that it would take dozens of seconds to render a real-shape water wave image, what we need now is real-time rendering, which requires at least 20 frames per second for smooth display of water waves. Considering the speed of computer computation, it is impossible for us to construct water waves based on sine functions or precise formulas. We cannot use multiplication or division, or trigonometric functions such as sin and cos, we can only use a fast algorithm to take an approximate value. Although this algorithm has some errors, we have to do this to meet the requirements of real-time animation.


First, we need to create two arrays buf1 [poolwidth * poolheight] And buf2 [poolwidth * poolheight] (poolwidth is the pixel width of the Pool Image and poolheight is the pixel of the pool image. height ), it is used to store the fluctuation data of the previous and the next moments of each vertex on the water surface. Because the fluctuation also represents the energy of the wave, we call these two arrays as the wave buffer. The water surface is a plane in the initial state, and the amplitude of each point is 0. Therefore, the initial values of these two arrays are equal to 0.


The following formula is used to calculate the amplitude:

Assume that such a formula exists, you can calculate the amplitude of a point at any time based on the four points around a point, namely, the front, the back, the left, and the right, and the amplitude of the point itself, we may use induction to find the amplitude of any point on the surface at any time. As shown in the left figure, the amplitude of x0 is not affected by the amplitude of x0, at the same time, it is affected by four points (x1, x2, X3, X4) from the front, back, left, and right around it (to simplify it, we ignore all other points, the influence of these four points on the x0 point can be said to be equal opportunities. We can assume that the formula for this time is:

X0' = A * (X1 + X2 + X3 + X4) + B * x0 (Formula 1)

A and B are undetermined coefficients, x0' is the amplitude of the next moment at x0, and x0, x1, x2, X3, and X4 are the amplitude of the current moment.

Next we will solve a and B.

Assume that the damping of water is 0. Under such ideal conditions, the total potential energy of water will remain unchanged, and water waves will fluctuate forever. That is to say, the sum of the amplitude of all vertices remains unchanged at any time. The following formula is obtained:

X0 '+ x1' +... + Xn' = x0 + X1 +... + Xn

Replace each vertex with Formula 1 and substitute it with the above formula to obtain:

(4A + B) * x0 + (4A + B) * X1 +... (4A + B) * xn = x0 + X1 +... + Xn => 4A
+ B = 1

Find out the simplest solution:A = 1/2, B =-1.

Because 1/2 can be performed using the shift operator ">" without multiplication or division, this group of solutions is the most suitable and fastest. The final formula is:

X0' = (X1 + X2 + X3 + X4)/2-x0

Well, with the above approximate formula, you can extend it to the following general conclusion: if we know the volatility of any point on the water at a given moment, then, at the next moment, the amplitude of any point is equal to the amplitude of the four points before, after, left, and right next to the point divided by 2, and then minus the amplitude of the point.

It should be noted that there is damping in the water. Otherwise, using the above formula, once you add a source in the water, the water will never stop fluctuating. Therefore, we also need to attenuation the amplitude data so that after each point is calculated, the amplitude is reduced by a certain proportion than the ideal value. This attenuation rate has been tested. It is suitable to use 1/32, that is, 1/2 ^ 5. It can be quickly obtained through the shift operation.

By now, the most difficult part of the water wave special effect algorithm has been clarified. The following is the code for calculating the amplitude data in the android source program:

// The amplitude algorithm for the next time of a certain point is: the amplitude of the top, bottom, left, and right minus the current amplitude, I .e., // x0' = (X1 + X2 + X3 + X4) /2-x0 // + ---- X3 ---- + // + | + // X1 --- x0 ---- X2 // + | + // + ---- X4 ---- + void ripplespread () {int pixels = m_width * (m_height-1); For (INT I = m_width; I <pixels; ++ I) {// wave energy diffusion: the amplitude and half of the amplitude at the top, bottom, left, and right minus the current amplitude // x0' = (X1 + X2 + X3 + X4)/2-x0 // m_buf2 [I] = (short) (m_buf1 [I-1] + m_buf1 [I + 1] + m_buf1 [I-m_width] + m_buf1 [I + m_width])> 1) -m_buf2 [I]); // the wave energy attenuation is 1/32 m_buf2 [I]-= m_buf2 [I]> 5;} // The short [] temp = m_buf1; m_buf1 = m_buf2; m_buf2 = temp ;}

Rendering:

Then we can render the page based on the calculated amplitude data.

Because of the refraction of water, when the water surface is not perpendicular to our line of sight, the underwater scenery we see is not at the bottom of the observation point, but there is a certain offset. The degree of offset is related to the slope of water waves, the refractive index of water, and the depth of water. If accurate calculations are required, it is obviously unrealistic. Similarly, we only need to do linear approximation. Because the water surface is tilted, the offset of the Underwater scene is larger, we can approximate the amplitude difference between the front, back, and left of a point on the water surface to represent the offset of the Underwater scene.

In the program, the original image is loaded with one page and rendered with another page. First, get the pointers SRC and DST pointing to the two page memory areas, and then copy each pixel in the original image to the rendering page according to the offset. The code for page rendering is as follows:

Void ripplerender () {int offset; int I = m_width; int length = m_width * m_height; For (INT y = 1; y <m_height-1; ++ y) {for (INT x = 0; x <m_width; ++ X, ++ I) {// calculate the memory address offset of the Offset pixel and the original pixel: // offset = width * yoffset + xoffset offset = (m_width * (m_buf1 [I-m_width]-m_buf1 [I + m_width]) + (m_buf1 [I-1]-m_buf1 [I + 1]); // determines whether the coordinates are in the range. if (I + Offset> 0 & I + offset <length) {m_bitmap2 [I] = m_bitmap1 [I + offset];} else {m_bitmap2 [I] = m_bitmap1 [I] ;}}

Add a source:
As the saying goes: in order to form a water wave, we must add a source to the pool. You can imagine putting a stone into the water, the size and energy of the source are related to the radius of the stone and the strength of the stone you throw. Knowing this, we only need to modify the wave energy data buffer Buf so that it can bring a negative "sharp pulse" at the place where the stone enters the water, that is, let the Buf [x, y] =-n. After the experiment, the range of N is (32 ~ 128.

To control the source RADIUS, you only need to draw a circle with the radius of the stone as the center point of the stone entering the water, let all vertices in this circle come with such a negative "sharp pulse" (here we have done an approximate processing ).

The code for adding a source code is as follows:

// Stonesize: source RADIUS // stoneweight: source energy // void dropstone (int x, int y, int stonesize, int stoneweight) {// determine whether the coordinates are in the range if (x + stonesize)> m_width | (Y + stonesize)> m_height | (X-stonesize) <0 | (Y-stonesize) <0) {return;} int value = stonesize * stonesize; short weight = (short)-stoneweight; 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) <value) {m_buf1 [m_width * posy + posx] = weight ;}}}}

If we want to simulate the ripple effect caused by water stroke, we need to add a new algorithm function breasenhamdrop.

Void dropstoneline (int x, int y, int stonesize, int stoneweight) {// determine whether the coordinates are within the screen range if (x + stonesize)> m_width | (Y + stonesize)> m_height | (X-stonesize) <0 | (Y-stonesize) <0) {return ;} for (INT posx = x-stonesize; posx <X + stonesize; ++ posx) {for (INT posy = Y-stonesize; posy <Y + stonesize; ++ posy) {m_buf1 [m_width * posy + posx] =-40 ;}}// XS, YS: Start Point, XE, ye: End Point // Size: wave source RADIUS, weight: wave source energy void breasenhamdrop (int xs, int ys, int XE, int ye, int size, int weight) {int dx = Xe-xs; int DY = Ye-Ys; dx = (dx> = 0 )? DX:-DX; DY = (dy> = 0 )? DY:-dy; If (dx = 0 & DY = 0) {dropstoneline (XS, ys, size, weight);} else if (dx = 0) {int yinc = (Ye-ys! = 0 )? 1:-1; for (INT I = 0; I <dy; ++ I) {dropstoneline (XS, ys, size, weight); ys + = yinc ;}} else if (DY = 0) {int xinc = (Xe-xs! = 0 )? 1:-1; for (INT I = 0; I <DX; ++ I) {dropstoneline (XS, ys, size, weight); Xs + = xinc ;}} else if (dx> Dy) {int P = (dy <1)-DX; int INC1 = (dy <1); int inc2 = (dy-dx) <1); int xinc = (Xe-xs! = 0 )? 1:-1; int yinc = (Ye-ys! = 0 )? 1:-1; for (INT I = 0; I <DX; ++ I) {dropstoneline (XS, ys, size, weight); Xs + = xinc; if (p <0) {P + = INC1;} else {ys + = yinc; P + = inc2 ;}} else {int P = (DX <1) -dy; int INC1 = (DX <1); int inc2 = (DX-dy) <1); int xinc = (Xe-xs! = 0 )? 1:-1; int yinc = (Ye-ys! = 0 )? 1:-1; for (INT I = 0; I <dy; ++ I) {dropstoneline (XS, ys, size, weight); ys + = yinc; if (p <0) {P + = INC1;} else {Xs + = xinc; P + = inc2 ;}}}}

Class diagram:

Engineering source code download: http://download.csdn.net/detail/zhang957411207/4568353

The end

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.