EDIT: something is wrong with the image server right now, the pictures are unavaileable, hopefully only temporary.
Continued from:
http://www.gamedev.net/community/forums/topic.asp?topic_id=278463
Quite a few people have asked me on these and other forums and mailed about how I made the shore line foam in Paradise Island.
So I decided to make one good explanation and direct them all here, so everyone else can have a look see too :). But be warned before you read further - this is not the best, and in my opinion not even a good way to do this, you should improve a lot more before using this in a project of your own, but feel free to do whatever you want with this. But this may provide a good start for those that dont know where to begin. Ok, so here it goes:
Step 1: Get The Foam Triangles
Basically its just: loop through all terrain triangles and mark those that have atleast one vertex over the water level and atleast one under/equal to the water level. Copy them into the foam triangles, and now we have the basis for the foam. What we get is this line:
Step 2: Set Under Water Verts To Water Level
Well, do just that, set the Y coord of all the foam underwater vertexes to WaterHeight.
Step 3: Relax The Foam Triangles
This means, make the line smoother, to get something like this:
I do this like that (actual code :) )
MoveOverWaterVertsFromUnderWaterNeibhours(0.25f);
MoveUnderWaterVertsFromOverWaterNeibhours(0.25f);
MoveUnderWaterVertsToUnderWaterNeibhours(1.0f);
MoveOverWaterVertsToOverWaterNeibhours(1.0f);
MoveUnderWaterVertsToUnderWaterNeibhours(1.0f);
MoveOverWaterVertsToOverWaterNeibhours(1.0f);
The floats mean how much weight does the vertex give to himself for each neibhour (all the neibhours are 1.0f)
Heres some source so you understand what I'm talking about:
void classFoam::MoveToOverWaterNeibhours(int VertNum,float OwnWeight)
{
float Weight=(float(Verts[VertNum].Neibhours.OverCount))*OwnWeight;
//weight=OwnWeight*NeibhourCount
Vector Sum;
Sum.Set(Verts[VertNum].x,Verts[VertNum].y,Verts[VertNum].z);
Sum.Multiply(Weight);
int num;
for(num=0;num<Verts[VertNum].Neibhours.OverCount;num++)
{
Weight+=1.0f;
Sum.Add(Verts[Verts[VertNum].Neibhours.Over[num]].x,
Verts[Verts[VertNum].Neibhours.Over[num]].y,
Verts[Verts[VertNum].Neibhours.Over[num]].z);
}
//add the position of each neibhour and add 1.0f to the main weight
if(Weight)
{
Sum.Divide(Weight);
Verts[VertNum].x=Sum.x;
Verts[VertNum].z=Sum.z;
}
}
//divide the sum with the weight
and
void classFoam::MoveFromOverWaterNeibhours(int VertNum,float
float Weight=(float(Verts[VertNum].Neibhours.OverCount))*OwnWeight;
GiGaMath_Vector Sum;
Sum.Set(Verts[VertNum].x,Verts[VertNum].y,Verts[VertNum].z);
Sum.Multiply(Weight);
int num;
for(num=0;num<Verts[VertNum].Neibhours.OverCount;num++)
{
Weight+=1.0f;
Sum.Add(Verts[Verts[VertNum].Neibhours.Over[num]].x,
Verts[Verts[VertNum].Neibhours.Over[num]].y,
Verts[Verts[VertNum].Neibhours.Over[num]].z);
}
if(Weight)
{
Sum.Divide(Weight);
Verts[VertNum].x=Verts[VertNum].x+(Verts[VertNum].x-Sum.x);
Verts[VertNum].z=Verts[VertNum].z+(Verts[VertNum].z-Sum.z);
}
the other functions are similar. As you can see in the pic, the foam triangles intersect with the terrain and we need to fix that! So next -
Step 4: Find Over Water Vertex Y Coords
So we just loop through all vertexes and if they are over water vertexes, set that Y coord to terrain height at those X,Z coords. We get this:
As you can see, we still get some foam/terrain intersections, so we
Step 5: Fix Terrain Foam Collisions
What I do here is just - loop trough all triangles, check if any of their edges intersect with the terrain and if they do, raise their vertexes by a small ammount. Then check again... and so on, until I have corrected all intersections. What we get is this:
Note: I dont really kill ALL the intersections, since that would sometimes mean raising the foam too high (sometimes the player could even see under it) but I often leave small intersections, since they are actuallly hard to notice with all the waving and alpha blending. Some may, of course, look real ugly, but to avoid that you have to make the shore line real flat...
And the last but not least
Step 6: Texture Coordinate generation
I will just explain what I have theoretised here, and dont give any of my ugly code :)
What we get is this:
But how de do that? Real simple, actually!
Have a look at this pic:
Say we start generating from vertex 1; we set its U coord to 0.0f; then proceed to its same type (underwater) neibhour - vertex 2; get the distance between them, lets say its 1.2f; and lets say you want your foam texture to tile one time over the distance of 2.0f; so we get the U coords: 0.0f+1.2f/2.0f=0.6f;
Then we proceed to vertex 3 - lets say the distance between 2-3 is 1.5f; so we calculate the U coord: 0.6f+1.5f/2.0f=1.35f;
And so on and so on and so on, you just divide the distance to the next vertex by the texture tile distance and add current vertexes U coord to it. Then we do the same for over water vertexes, starting from the one attached to our vertex 1 so we dont get foam line bottom/top offset. One bug I have left is where the circle ends... I usually correct that by hand. The next part is the V coord generation, which is a bit trickyer, but still very simple. First give each vertex a time offset value for the calculation of the Y coord, make sure that each underwater vert has the same offset as the closest overwater vert, and that neibhouring same type verts dont have too much difference in their offsets. Heres some possible offset values:
And when you render you calculate the V coord for each vert like so:
A=-fabs(TIMES*sin(StartVCoef+Time));
V=1.0f+TIMES+A; //for over water verts
V=A; //for underwater verts
And you can also set the alpha value of that vertex to: -A/TIMES;
Heres an illustration of why, and what does it all mean:
The big quad is two of the foam triangles, and the small quad is the texture stretching over them so you see you have to set the vertical tiling to GL_CLAMP_TO_EDGE or whatever is the DX equivalent. Phase one is when the wave has reached the shore - opaque, and phase 2 is when the wave is in the water - transparent. The green numbers are the V coords needed at that point so the texture stretches in the desired way. TIMES = how many times you want the texture to stretch vertically over the triangle minus 1.0;
Please ask if anything remains unclear, and I guess there will be a lot of questions since I'm usually bad at explaining things :)
[Edited by - Bouga on November 11, 2004 2:39:16 PM]