Quote:Original post by Promit
As for the skirts people, would one of you please detail exactly how skirts work? My understanding leads me to believe that they're a pretty miserable hack, and I'd like to be on the same page as everyone else while discussing this.
I'll have a go. It's now 4am, and this is a bit of a brain dump, I apologise. I might edit it for readability tomorrow.
Essentially skirts are triangle strips that bound each patch. Their top edge follows the existing vertices and their bottom edge uses the same x,z but displaces the y by some amount. Thus, when patches with different LOD are drawn next to one another, the user sees the skirt instead of a crack. This looks really crappy unless the screenspace error is small. I figure you already know this much [smile].
(as an aside, I wanted to use triangle fans for the skirts to keep it 'simple' - one centre vert displaced and one at either corner. As it turned out this doesn't handle all situations well, and is in fact more complex to code than triangle strips. Extra geometry helps balance the pipline too.)
As such, skirts are much better suited for Chunked LOD than for geomipmapping, as the mesh decimation scheme for geomipmapping doesn't take screenspace error into account. I've written my terrain stuff so that it should be fairly simple to drop in a diferent tesselation/decimation scheme, so skirts are more 'portable' in that sense.
That said, with max screen space error set to less than about 20 pixels, it's still unnoticeable for most heightmaps (at least all the ones I've tested. The ones where it would mess up would be ones with high frequency changes in altitude, but GMM falls down there anyway.) It's important to use the same texture coordinates and normals as for the existing vertices to fool the eye into thinking that it's a smooth continuation. In fact I'm faily sure it's using the same normal that completes the illusion.
The major downside to skirts is they eat extra fill rate. I draw mine as the very last thing in the scene, so in most cases it's just a ztest and discard instead of filling the same pixels multiple times. The only skirt fragments to get filled are where the background would otherwise show through.
The amount by which the skirts's y is displaced should be as small as possible to conserve fillrate (well, ztest rate... but you know what I mean). It needs to be longer than any possible simplifcation of the edge. Sounds simple, but I've yet to find a metric I'm happy with. Max geometric error of the verts in the edge seems a good indicator, but thats a measure of the LOD patch's difference from the full detail mesh, not a lower detail mesh, which may actually be more...
The idea behind them being longer than any possible simplification of the mesh, is that the same skirt can then be used no matter what the difference in LOD of the neighbouring patches. The best thing about them is the implicit knowledge that you will only ever see max_screen_error pixels of a skirt.
I implemented my skirts as display lists. This makes them fast, and hopefully take less vid memory than having lots of index buffers, though I can't be sure as I've no idea what kind of storage overhead display lists impose. They certainly save AGP bandwidth over updating the indices regularly.
At the moment I draw a skirt for every patch edge. This is far from optimal, but the framerate hit isn't too bad. Really I should only draw those edges that border a patch with different LOD and face the viewer. I have an idea for a fast way to work out which skirts face the viewer and draw only them, but it relies on a quadtree trick I haven't quite solidified yet. I'll proably leave it until it's a problem, and then decide if it's worth trading the cpu time for the gpu time.
Quote:Original post by Promit
I guess my main thing is that I can cope with the patch levels of detail as they are, and I don't need to impose the rather common restriction that most people have; that is, that a neighbor's level of detail can differ by at most one level. I don't like that restriction, as it artificially increases the detail levels of patches.
This is the main reason I went for skirts - they avoid the restriction and are simple to implement. In short, they're not perfect, but give the benefit of scaleability and are much simpler to implement than the alternative (IMHO).
So there you go - not perfect, but the right tool for the job in my case. I'm not sure if they're any less perfect than index tricks, and I'd be interested to find out. Chances are though that time I could spend trying it would be better spent making it use a better (preprocess) decimation scheme and sticking to skirts.
here are some shots of my skirts taken while implementing them, which may be useful to illustrate.