Tuesday, July 13, 2010

Recast Area Types Per Triangle

I just committed a change (R185) which allows you to pass area type per triangle for rasterization.

API Changes

From Flags to Areas

Firstly, the flags are now gone from the rasterization functions and area type is used instead. Now same concept of marking things walkable or not is used throughout the pipeline.

If you want to make a triangle non-passable, use area type of RC_NULL_AREA. If you don't care about area types at all, you should use general RC_WALKABLE_AREA.

rcMarkWalkableTriangles() uses that area type that to keep the existing behavior. I also added rcClearUnwalkableTriangles() which does the opposite, that is sets the area types of a triangle to RC_NULL_AREA if the triangle slope is too steep. Handy if you have an array of area types to start with.

The change to the rasterize methods is minimal, instead of passing a flags now you pass an area type.

Compacting Heightfield

When the heightfield is processed to compact heightfield, there used to be a flag parameter. This is gone now, so flags parameter from rcGetHeightFieldSpanCount() and rcBuildCompactHeightfield() are omitted now. Every voxel that has are type other than RC_NULL_AREA will be included in the span count as well as in the compact heightfield.

Filtering

The area eroding function used to have a trace of some old ideas of mine which required you to pass area type to it. The area type is removed now. I changed the function name to rcErodeWalkableArea() to better reflect what it is actually doing.

Aliasing

The new feature comes with a new set of problems. One problem is aliasing. In many ways voxelization works the same way as z-buffer. When surfaces are intersecting each other at low angle or almost parallel we will get aliasing error usually referred as "z-fighting".

This can cause nasty noise at the boundaries of different types of areas. One simple way to fight this is to apply media filter to remove the speckles. I have added rcMedianFilterWalkableArea() just for that.

Median filtering will smooth things out a bit, so if you want to keep as sharp as possible outlines for rcMarkConvexPolyArea() you may want to apply the filtering before you mark the areas. Otherwise I recommend to apply the filtering just before you build the distance field and build regions.

Median filtering is not super expensive, but not free either. On average add 1-2% to the generation time (that is, 10ms on 1000ms generation process).

Accuracy

In order to not to increase the memory footprint of voxelization process, I took some bits from the height range and moved them to the area types in rcSpan structure. This basically reduces the height range from 32k to 8k.

For majority of the users this is fine. One of my test levels which goes 6 stories above and below the ground uses max height of 1450 (human sized character, cell height 0.2).

If you run out of bits there, you can adjust the bits in rcSpan struct (remember to also change RC_SPAN_HEIGHT_BITS). This is likely to increase the rcSpan size from 8 bytes to 12 bytes (on 32 bit machines) and that will reflect in memory consumption.

Sorry for the API breakage, but I hope this will make things more flexible for many people!