[requested] Foam - how I did it...

Started by
13 comments, last by Bouga 19 years, 5 months ago
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]
"A screen buffer is worth a thousand char's" - me
Advertisement
Looks nice. I think you should talk with someone of the staff to make into an article here at gamedev.
You should never let your fears become the boundaries of your dreams.
Yeah, very well written article, the explaination is very clear to me.
The assumption for ur method seems to be that the amplitude of the coastal water is very low, but that's ok, as amplitude of coastal waves is generally low.
Any way, thanks for posting this good article, and do think to send this to one of the GDnet staff.
Thank you :) Hmm, I dont think it is good enough to become an article.. atleast yet, mainly becouse of what you just said - it assumes some things about the shoreline - being quite flat for example, but maybe if I (or someone else) find a solution for some of the problems and add that to this, then maybe.. anyway, I wont be the judge of whether it is good enough to be an article, but if a moderator desides that it is, I will try to write a bit better explanation (was it really that clear?).
"A screen buffer is worth a thousand char's" - me
If it makes you feel any better about your algorithm, it's not too far removed from what I did on Empires: Dawn of the Modern World.

http://www.gamerankings.com/htmlpagesscreens/589675.asp?screenid=6
Wow, now thats a morale boost... that sure made me feel better about it :)
"A screen buffer is worth a thousand char's" - me
I cant se the images that come with the article... but you should really ask Gamedev to publish your article. Looks nice!

Luck!
Guimo
A great article ! I was currently trying to implement this feature without luck...
Thanks to you ;)

Chman
- Artist on the web -- Lwjgl Ressources & blog -
Nice. Very nice.

(FYI, "Neibhour" is spelled Neighbor. Well, in english anyways. (I understand, however, that many people didn't grow up learning english, or are kid mini-geniuses - I also make much worse mistakes trying to spell words in spanish, and german - and mis-spell a lot an english - this is just an FYI, since your example snippits use the mis-spelled version too ^_^. (Hey, at least it's consistant))).
Quote:Original post by MaulingMonkey
(FYI, "Neibhour" is spelled Neighbor. Well, in english anyways.


Neighbour for me :P

This topic is closed to new replies.

Advertisement