
- Upgraded doxyfile to latest format - Fixed a bunch of warnings and errors in docstrings that doxygen was complaining about - Added the doxygen-awesome theme to modernize the output - Removed a duplicate screenshot we'd had in the docs folder - Moved the RecastDemo screenshot into the Docs/images folder - Changed the doxygen main page to be the README.md since the dedicated main page file we had was nearly identical but out of date - Added CONTRIBUTING.md so it's part of the generated doxygen output - Removed duplicate license file to avoid confusion - Combined the FAQ with the Recast_api.txt, since the FAQ was essentially just better docs for the members of `rcConfig`
683 lines
23 KiB
Plaintext
683 lines
23 KiB
Plaintext
// This file contains the detail API documentation for
|
||
// elements defined in the Recast.h.
|
||
|
||
/**
|
||
|
||
@defgroup recast Recast
|
||
|
||
Members in this module are used to create mesh data that is then
|
||
used to create Detour navigation meshes.
|
||
|
||
The are a large number of possible ways to building navigation mesh data.
|
||
One of the simple piplines is as follows:
|
||
|
||
-# Prepare the input triangle mesh.
|
||
-# Build a #rcHeightfield.
|
||
-# Build a #rcCompactHeightfield.
|
||
-# Build a #rcContourSet.
|
||
-# Build a #rcPolyMesh.
|
||
-# Build a #rcPolyMeshDetail.
|
||
-# Use the rcPolyMesh and rcPolyMeshDetail to build a Detour navigation mesh
|
||
tile.
|
||
|
||
The general life-cycle of the main classes is as follows:
|
||
|
||
-# Allocate the object using the Recast allocator. (E.g. #rcAllocHeightfield)
|
||
-# Initialize or build the object. (E.g. #rcCreateHeightfield)
|
||
-# Update the object as needed. (E.g. #rcRasterizeTriangles)
|
||
-# Use the object as part of the pipeline.
|
||
-# Free the object using the Recast allocator. (E.g. #rcFreeHeightField)
|
||
|
||
@struct rcConfig
|
||
@par
|
||
|
||
The is a convenience structure that represents an aggregation of parameters
|
||
used at different stages in the Recast build process. Some
|
||
values are derived during the build process. Not all parameters
|
||
are used for all build processes.
|
||
|
||
Units are usually in voxels (vx) or world units (wu). The units for voxels,
|
||
grid size, and cell size are all based on the values of #cs and #ch.
|
||
|
||
In this documentation, the term 'field' refers to heightfield and
|
||
contour data structures that define spacial information using an integer
|
||
grid.
|
||
|
||
The upper and lower limits for the various parameters often depend on
|
||
the platform's floating point accuraccy as well as interdependencies between
|
||
the values of multiple parameters. See the individual parameter
|
||
documentation for details.
|
||
|
||
@note First you should decide the size of your agent's logical cylinder.
|
||
If your game world uses meters as units, a reasonable starting point for
|
||
a human-sized agent might be a radius of `0.4` and a height of `2.0`.
|
||
|
||
@var rcConfig::borderSize
|
||
@par
|
||
|
||
This value represents the the closest the walkable area of the heightfield
|
||
should come to the xz-plane AABB of the field. It does not have any
|
||
impact on the borders around internal obstructions.
|
||
|
||
@var rcConfig::tileSize
|
||
@par
|
||
|
||
This field is only used when building multi-tile meshes.
|
||
|
||
@var rcConfig::cs
|
||
@par
|
||
|
||
The voxelization cell size #cs defines the voxel size along both axes of
|
||
the ground plane: x and z in Recast. This value is usually derived from the
|
||
character radius `r`. A recommended starting value for #cs is either `r/2`
|
||
or `r/3`. Smaller values of #cs will increase rasterization resolution and
|
||
navmesh detail, but total generation time will increase exponentially. In
|
||
outdoor environments, `r/2` is often good enough. For indoor scenes with
|
||
tight spaces you might want the extra precision, so a value of `r/3` or
|
||
smaller may give better results.
|
||
|
||
The initial instinct is to reduce this value to something very close to zero
|
||
to maximize the detail of the generated navmesh. This quickly becomes a case
|
||
of diminishing returns, however. Beyond a certain point there's usually not
|
||
much perceptable difference in the generated navmesh, but huge increases in
|
||
generation time. This hinders your ability to quickly iterate on level
|
||
designs and provides little benefit. The general recommendation here is to
|
||
use as large a value for #cs as you can get away with.
|
||
|
||
#cs and #ch define voxel/grid/cell size. So their values have significant
|
||
side effects on all parameters defined in voxel units.
|
||
|
||
The minimum value for this parameter depends on the platform's floating point
|
||
accuracy, with the practical minimum usually around 0.05.
|
||
|
||
@var rcConfig::ch
|
||
@par
|
||
|
||
The voxelization cell height #ch is defined separately in order to allow for
|
||
greater precision in height tests. A good starting point for #ch is half the
|
||
#cs value. Smaller #ch values ensure that the navmesh properly connects areas
|
||
that are only separated by a small curb or ditch. If small holes are generated
|
||
in your navmesh around where there are discontinuities in height (for example,
|
||
stairs or curbs), you may want to decrease the cell height value to increase
|
||
the vertical rasterization precision of Recast.
|
||
|
||
#cs and #ch define voxel/grid/cell size. So their values have significant
|
||
side effects on all parameters defined in voxel units.
|
||
|
||
The minimum value for this parameter depends on the platform's floating point
|
||
accuracy, with the practical minimum usually around 0.05.
|
||
|
||
@var rcConfig::walkableSlopeAngle
|
||
@par
|
||
|
||
The parameter #walkableSlopeAngle is to filter out areas of the world where
|
||
the ground slope would be too steep for an agent to traverse. This value is
|
||
defined as a maximum angle in degrees that the surface normal of a polgyon
|
||
can differ from the world's up vector. This value must be within the range
|
||
`[0, 90]`.
|
||
|
||
The practical upper limit for this parameter is usually around 85 degrees.
|
||
|
||
@var rcConfig::walkableHeight
|
||
@par
|
||
|
||
This value defines the worldspace height `h` of the agent in voxels. Th value
|
||
of #walkableHeight should be calculated as `ceil(h / ch)`. Note this is based
|
||
on #ch not #cs since it's a height value.
|
||
|
||
Permits detection of overhangs in the source geometry that make the geometry
|
||
below un-walkable. The value is usually set to the maximum agent height.
|
||
|
||
@var rcConfig::walkableClimb
|
||
@par
|
||
|
||
The #walkableClimb value defines the maximum height of ledges and steps that
|
||
the agent can walk up. Given a designer-defined `maxClimb` distance in world
|
||
units, the value of #walkableClimb should be calculated as `ceil(maxClimb / ch)`.
|
||
Note that this is using #ch not #cs because it's a height-based value.
|
||
|
||
Allows the mesh to flow over low lying obstructions such as curbs and
|
||
up/down stairways. The value is usually set to how far up/down an agent can step.
|
||
|
||
@var rcConfig::walkableRadius
|
||
@par
|
||
|
||
The parameter #walkableRadius defines the worldspace agent radius `r` in voxels.
|
||
Most often, this value of #walkableRadius should be calculated as `ceil(r / cs)`.
|
||
Note this is based on #cs since the agent radius is always parallel to the ground
|
||
plane.
|
||
|
||
If the #walkableRadius value is greater than zero, the edges of the navmesh will
|
||
be pushed away from all obstacles by this amount.
|
||
|
||
A non-zero #walkableRadius allows for much simpler runtime navmesh collision checks.
|
||
The game only needs to check that the center point of the agent is contained within
|
||
a navmesh polygon. Without this erosion, runtime navigation checks need to collide
|
||
the geometric projection of the agent's logical cylinder onto the navmesh with the
|
||
boundary edges of the navmesh polygons.
|
||
|
||
In general, this is the closest any part of the final mesh should get to an
|
||
obstruction in the source geometry. It is usually set to the maximum
|
||
agent radius.
|
||
|
||
If you want to have tight-fitting navmesh, or want to reuse the same navmesh for
|
||
multiple agents with differing radii, you can use a `walkableRadius` value of zero.
|
||
Be advised though that you will need to perform your own collisions with the navmesh
|
||
edges, and odd edge cases issues in the mesh generation can potentially occur. For
|
||
these reasons, specifying a radius of zero is allowed but is not recommended.
|
||
|
||
@var rcConfig::maxEdgeLen
|
||
@par
|
||
|
||
In certain cases, long outer edges may decrease the quality of the resulting
|
||
triangulation, creating very long thin triangles. This can sometimes be
|
||
remedied by limiting the maximum edge length, causing the problematic long
|
||
edges to be broken up into smaller segments.
|
||
|
||
The parameter #maxEdgeLen defines the maximum edge length and is defined in
|
||
terms of voxels. A good value for #maxEdgeLen is something like
|
||
`walkableRadius * 8`. A good way to adjust this value is to first set it really
|
||
high and see if your data creates long edges. If it does, decrease #maxEdgeLen
|
||
until you find the largest value which improves the resulting tesselation.
|
||
|
||
Extra vertices will be inserted as needed to keep contour edges below this
|
||
length. A value of zero effectively disables this feature.
|
||
|
||
@var rcConfig::maxSimplificationError
|
||
@par
|
||
|
||
When the rasterized areas are converted back to a vectorized representation,
|
||
the #maxSimplificationError describes how loosely the simplification is done.
|
||
The simplification process uses the
|
||
<a href="https://en.wikipedia.org/wiki/Ramer–Douglas–Peucker_algorithm">Ramer–Douglas-Peucker algorithm</a>,
|
||
and this value describes the max deviation in voxels.
|
||
|
||
Good values for #maxSimplificationError are in the range `[1.1, 1.5]`.
|
||
A value of `1.3` is a good starting point and usually yields good results.
|
||
If the value is less than `1.1`, some sawtoothing starts to appear at the
|
||
generated edges. If the value is more than `1.5`, the mesh simplification
|
||
starts to cut some corners it shouldn't.
|
||
|
||
The effect of this parameter only applies to the xz-plane.
|
||
|
||
@var rcConfig::minRegionArea
|
||
@par
|
||
|
||
Watershed partitioning is really prone to noise in the input distance field.
|
||
In order to get nicer areas, the areas are merged and small disconnected areas
|
||
are removed after the water shed partitioning. The parameter #minRegionArea
|
||
describes the minimum isolated region size that is still kept. A region is
|
||
removed if the number of voxels in the region is less than the square of
|
||
#minRegionArea.
|
||
|
||
Any regions that are smaller than this area will be marked as unwalkable.
|
||
This is useful in removing useless regions that can sometimes form on
|
||
geometry such as table tops, box tops, etc.
|
||
|
||
@var rcConfig::maxVertsPerPoly
|
||
@par
|
||
|
||
If the mesh data is to be used to construct a Detour navigation mesh, then the upper limit
|
||
is limited to <= #DT_VERTS_PER_POLYGON.
|
||
|
||
@var rcConfig::mergeRegionArea
|
||
@par
|
||
|
||
The triangulation process works best with small, localized voxel regions.
|
||
The parameter #mergeRegionArea controls the maximum voxel area of a region
|
||
that is allowed to be merged with another region. If you see small patches
|
||
missing here and there, you could lower the #minRegionArea value.
|
||
|
||
@struct rcHeightfield
|
||
@par
|
||
|
||
The grid of a heightfield is layed out on the xz-plane based on the
|
||
value of #cs. Spans exist within the grid columns with the span
|
||
min/max values at increments of #ch from the base of the grid. The smallest
|
||
possible span size is <tt>(#cs width) * (#cs depth) * (#ch height)</tt>. (Which is a single voxel.)
|
||
|
||
The standard process for buidling a heightfield is to allocate it using
|
||
#rcAllocHeightfield, initialize it using #rcCreateHeightfield, then
|
||
add spans using the various helper functions such as #rcRasterizeTriangle.
|
||
|
||
Building a heightfield is one of the first steps in creating a polygon mesh
|
||
from source geometry. After it is populated, it is used to build a
|
||
rcCompactHeightfield.
|
||
|
||
Example of iterating the spans in a heightfield:
|
||
@code
|
||
// Where hf is a reference to an heightfield object.
|
||
|
||
const float* orig = hf.bmin;
|
||
const float cs = hf.cs;
|
||
const float ch = hf.ch;
|
||
|
||
const int w = hf.width;
|
||
const int h = hf.height;
|
||
|
||
for (int y = 0; y < h; ++y)
|
||
{
|
||
for (int x = 0; x < w; ++x)
|
||
{
|
||
// Deriving the minimum corner of the grid location.
|
||
float fx = orig[0] + x*cs;
|
||
float fz = orig[2] + y*cs;
|
||
// The base span in the column. (May be null.)
|
||
const rcSpan* s = hf.spans[x + y*w];
|
||
while (s)
|
||
{
|
||
// Detriving the minium and maximum world position of the span.
|
||
float fymin = orig[1]+s->smin*ch;
|
||
float fymax = orig[1] + s->smax*ch;
|
||
// Do other things with the span before moving up the column.
|
||
s = s->next;
|
||
}
|
||
}
|
||
}
|
||
@endcode
|
||
|
||
@see rcAllocHeightfield, rcFreeHeightField, rcCreateHeightfield
|
||
|
||
@struct rcCompactCell
|
||
@par
|
||
|
||
See the rcCompactHeightfield documentation for an example of how compact cells
|
||
are used to iterate the heightfield.
|
||
|
||
Useful instances of this type can only by obtained from a #rcCompactHeightfield object.
|
||
|
||
@see rcCompactHeightfield
|
||
|
||
@struct rcCompactSpan
|
||
@par
|
||
|
||
The span represents open, unobstructed space within a compact heightfield column.
|
||
See the rcCompactHeightfield documentation for an example of iterating spans and searching
|
||
span connections.
|
||
|
||
Useful instances of this type can only by obtained from a #rcCompactHeightfield object.
|
||
|
||
@see rcCompactHeightfield
|
||
|
||
|
||
@struct rcCompactHeightfield
|
||
@par
|
||
|
||
For this type of heightfield, the spans represent the open (unobstructed)
|
||
space above the solid surfaces of a voxel field. It is usually created from
|
||
a #rcHeightfield object. Data is stored in a compact, efficient manner,
|
||
but the structure is not condusive to adding and removing spans.
|
||
|
||
The standard process for buidling a compact heightfield is to allocate it
|
||
using #rcAllocCompactHeightfield, build it using #rcBuildCompactHeightfield,
|
||
then run it through the various helper functions to generate neighbor
|
||
and region data.
|
||
|
||
Connected neighbor spans form non-overlapping surfaces. When neighbor
|
||
information is generated, spans will include data that can be used to
|
||
locate axis-neighbors. Axis-neighbors are connected
|
||
spans that are offset from the current cell column as follows:
|
||
<pre>
|
||
Direction 0 = (-1, 0)
|
||
Direction 1 = (0, 1)
|
||
Direction 2 = (1, 0)
|
||
Direction 3 = (0, -1)
|
||
</pre>
|
||
|
||
Example of iterating and inspecting spans, including connected neighbors:
|
||
|
||
@code
|
||
// Where chf is an instance of a rcCompactHeightfield.
|
||
|
||
const float cs = chf.cs;
|
||
const float ch = chf.ch;
|
||
|
||
for (int y = 0; y < chf.height; ++y)
|
||
{
|
||
for (int x = 0; x < chf.width; ++x)
|
||
{
|
||
// Deriving the minimum corner of the grid location.
|
||
const float fx = chf.bmin[0] + x*cs;
|
||
const float fz = chf.bmin[2] + y*cs;
|
||
|
||
// Get the cell for the grid location then iterate
|
||
// up the column.
|
||
const rcCompactCell& c = chf.cells[x+y*chf.width];
|
||
for (unsigned i = c.index, ni = c.index+c.count; i < ni; ++i)
|
||
{
|
||
const rcCompactSpan& s = chf.spans[i];
|
||
|
||
Deriving the minimum (floor) of the span.
|
||
const float fy = chf.bmin[1] + (s.y+1)*ch;
|
||
|
||
// Testing the area assignment of the span.
|
||
if (chf.areas[i] == RC_WALKABLE_AREA)
|
||
{
|
||
// The span is in the default 'walkable area'.
|
||
}
|
||
else if (chf.areas[i] == RC_NULL_AREA)
|
||
{
|
||
// The surface is not considered walkable.
|
||
// E.g. It was filtered out during the build processes.
|
||
}
|
||
else
|
||
{
|
||
// Do something. (Only applicable for custom build
|
||
// build processes.)
|
||
}
|
||
|
||
// Iterating the connected axis-neighbor spans.
|
||
for (int dir = 0; dir < 4; ++dir)
|
||
{
|
||
if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
|
||
{
|
||
// There is a neighbor in this direction.
|
||
const int nx = x + rcGetDirOffsetX(dir);
|
||
const int ny = y + rcGetDirOffsetY(dir);
|
||
const int ni = (int)chf.cells[nx+ny*w].index + rcGetCon(s, 0);
|
||
const rcCompactSpan& ns = chf.spans[ni];
|
||
// Do something with the neighbor span.
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
@endcode
|
||
|
||
@see rcAllocCompactHeightfield, rcFreeCompactHeightfield, rcBuildCompactHeightfield
|
||
|
||
@struct rcContour
|
||
@par
|
||
|
||
A contour only exists within the context of a #rcContourSet object.
|
||
|
||
While the height of the contour's border may vary, the contour will always
|
||
form a simple polygon when projected onto the xz-plane.
|
||
|
||
Example of converting vertices into world space:
|
||
|
||
@code
|
||
// Where cset is the rcContourSet object to which the contour belongs.
|
||
float worldX = cset.bmin[0] + vertX * cset.cs;
|
||
float worldY = cset.bmin[1] + vertY * cset.ch;
|
||
float worldZ = cset.bmin[2] + vertZ * cset.cs;
|
||
@endcode
|
||
|
||
@see rcContourSet
|
||
|
||
@var rcContour::verts
|
||
@par
|
||
|
||
The simplified contour is a version of the raw contour with all
|
||
'unnecessary' vertices removed. Whether a vertex is
|
||
considered unnecessary depends on the contour build process.
|
||
|
||
The data format is as follows: (x, y, z, r) * #nverts
|
||
|
||
A contour edge is formed by the current and next vertex. The r-value
|
||
represents region and connection information for the edge. For example:
|
||
|
||
@code
|
||
int r = verts[i*4+3];
|
||
|
||
int regionId = r & RC_CONTOUR_REG_MASK;
|
||
|
||
if (r & RC_BORDER_VERTEX)
|
||
{
|
||
// The edge represents a solid border.
|
||
}
|
||
|
||
if (r & RC_AREA_BORDER)
|
||
{
|
||
// The edge represents a transition between different areas.
|
||
}
|
||
@endcode
|
||
|
||
@var rcContour::rverts
|
||
@par
|
||
|
||
See #verts for information on element layout.
|
||
|
||
@struct rcContourSet
|
||
@par
|
||
|
||
All contours within the set share the minimum bounds and cell sizes of the set.
|
||
|
||
The standard process for building a contour set is to allocate it
|
||
using #rcAllocContourSet, then initialize it using #rcBuildContours.
|
||
|
||
@see rcAllocContourSet, rcFreeContourSet, rcBuildContours
|
||
|
||
@struct rcPolyMesh
|
||
@par
|
||
|
||
A mesh of potentially overlapping convex polygons of between three
|
||
and #nvp vertices. The mesh exists within the context of an axis-aligned
|
||
bounding box (AABB) with vertices laid out in an evenly spaced grid, based
|
||
on the values of #cs and #ch.
|
||
|
||
The standard process for building a contour set is to allocate it using
|
||
#rcAllocPolyMesh, the initialize it using #rcBuildPolyMesh
|
||
|
||
Example of iterating the polygons:
|
||
|
||
@code
|
||
// Where mesh is a reference to a rcPolyMesh object.
|
||
|
||
const int nvp = mesh.nvp;
|
||
const float cs = mesh.cs;
|
||
const float ch = mesh.ch;
|
||
const float* orig = mesh.bmin;
|
||
|
||
for (int i = 0; i < mesh.npolys; ++i)
|
||
{
|
||
const unsigned short* p = &mesh.polys[i*nvp*2];
|
||
|
||
// Iterate the vertices.
|
||
unsigned short vi[3]; // The vertex indices.
|
||
for (int j = 0; j < nvp; ++j)
|
||
{
|
||
if (p[j] == RC_MESH_NULL_IDX)
|
||
break; // End of vertices.
|
||
|
||
if (p[j + nvp] == RC_MESH_NULL_IDX)
|
||
{
|
||
// The edge beginning with this vertex is a solid border.
|
||
}
|
||
else
|
||
{
|
||
// The edge beginning with this vertex connects to
|
||
// polygon p[j + nvp].
|
||
}
|
||
|
||
// Convert to world space.
|
||
const unsigned short* v = &mesh.verts[p[j]*3];
|
||
const float x = orig[0] + v[0]*cs;
|
||
const float y = orig[1] + v[1]*ch;
|
||
const float z = orig[2] + v[2]*cs;
|
||
// Do something with the vertices.
|
||
}
|
||
}
|
||
@endcode
|
||
|
||
@see rcAllocPolyMesh, rcFreePolyMesh, rcBuildPolyMesh
|
||
|
||
@var rcPolyMesh::verts
|
||
@par
|
||
|
||
The values of #bmin ,#cs, and #ch are used to convert vertex coordinates
|
||
to world space as follows:
|
||
|
||
@code
|
||
float worldX = bmin[0] + verts[i*3+0] * cs
|
||
float worldY = bmin[1] + verts[i*3+1] * ch
|
||
float worldZ = bmin[2] + verts[i*3+2] * cs
|
||
@endcode
|
||
|
||
@var rcPolyMesh::polys
|
||
@par
|
||
|
||
Each entry is <tt>2 * #nvp</tt> in length. The first half of the entry
|
||
contains the indices of the polygon. The first instance of #RC_MESH_NULL_IDX
|
||
indicates the end of the indices for the entry. The second half contains
|
||
indices to neighbor polygons. A value of #RC_MESH_NULL_IDX indicates no
|
||
connection for the associated edge. (I.e. The edge is a solid border.)
|
||
|
||
For example:
|
||
<pre>
|
||
nvp = 6
|
||
For the entry: (1, 3, 4, 8, RC_MESH_NULL_IDX, RC_MESH_NULL_IDX,
|
||
18, RC_MESH_NULL_IDX , 21, RC_MESH_NULL_IDX, RC_MESH_NULL_IDX, RC_MESH_NULL_IDX)
|
||
|
||
(1, 3, 4, 8) defines a polygon with 4 vertices.
|
||
Edge 1->3 is shared with polygon 18.
|
||
Edge 4->8 is shared with polygon 21.
|
||
Edges 3->4 and 4->8 are border edges not shared with any other polygon.
|
||
</pre>
|
||
|
||
@var rcPolyMesh::areas
|
||
@par
|
||
|
||
The standard build process assigns the value of #RC_WALKABLE_AREA to all walkable polygons.
|
||
This value can then be changed to meet user requirements.
|
||
|
||
@struct rcPolyMeshDetail
|
||
@par
|
||
|
||
The detail mesh is made up of triangle sub-meshes that provide extra
|
||
height detail for each polygon in its assoicated polygon mesh.
|
||
|
||
The standard process for building a detail mesh is to allocate it
|
||
using #rcAllocPolyMeshDetail, then build it using #rcBuildPolyMeshDetail.
|
||
|
||
See the individual field definitions for details realted to the structure
|
||
the mesh.
|
||
|
||
@see rcAllocPolyMeshDetail, rcFreePolyMeshDetail, rcBuildPolyMeshDetail, rcPolyMesh
|
||
|
||
@var rcPolyMeshDetail::meshes
|
||
@par
|
||
|
||
[(baseVertIndex, vertCount, baseTriIndex, triCount) * #nmeshes]
|
||
|
||
Maximum number of vertices per sub-mesh: 127<br/>
|
||
Maximum number of triangles per sub-mesh: 255
|
||
|
||
The sub-meshes are stored in the same order as the polygons from the
|
||
rcPolyMesh they represent. E.g. rcPolyMeshDetail sub-mesh 5 is associated
|
||
with #rcPolyMesh polygon 5.
|
||
|
||
Example of iterating the triangles in a sub-mesh.
|
||
|
||
@code
|
||
// Where dmesh is a reference to a rcPolyMeshDetail object.
|
||
|
||
// Iterate the sub-meshes. (One for each source polygon.)
|
||
for (int i = 0; i < dmesh.nmeshes; ++i)
|
||
{
|
||
const unsigned int* meshDef = &dmesh.meshes[i*4];
|
||
const unsigned int baseVerts = meshDef[0];
|
||
const unsigned int baseTri = meshDef[2];
|
||
const int ntris = (int)meshDef[3];
|
||
|
||
const float* verts = &dmesh.verts[baseVerts*3];
|
||
const unsigned char* tris = &dmesh.tris[baseTri*4];
|
||
|
||
// Iterate the sub-mesh's triangles.
|
||
for (int j = 0; j < ntris; ++j)
|
||
{
|
||
const float x = verts[tris[j*4+0]*3];
|
||
const float y = verts[tris[j*4+1]*3];
|
||
const float z = verts[tris[j*4+2]*3];
|
||
// Do something with the vertex.
|
||
}
|
||
}
|
||
@endcode
|
||
|
||
@var rcPolyMeshDetail::verts
|
||
@par
|
||
|
||
[(x, y, z) * #nverts]
|
||
|
||
The vertices are grouped by sub-mesh and will contain duplicates since
|
||
each sub-mesh is independently defined.
|
||
|
||
The first group of vertices for each sub-mesh are in the same order as
|
||
the vertices for the sub-mesh's associated PolyMesh polygon. These
|
||
vertices are followed by any additional detail vertices. So it the
|
||
associated polygon has 5 vertices, the sub-mesh will have a minimum
|
||
of 5 vertices and the first 5 vertices will be equivalent to the 5
|
||
polygon vertices.
|
||
|
||
@var rcPolyMeshDetail::tris
|
||
@par
|
||
|
||
[(vertIndexA, vertIndexB, vertIndexC, flags) * #ntris]
|
||
|
||
The triangles are grouped by sub-mesh.
|
||
|
||
<b>Vertex Indices</b>
|
||
|
||
The vertex indices in the triangle array are local to the sub-mesh, not global.
|
||
To translate into an global index in the vertices array, the values must be
|
||
offset by the sub-mesh's base vertex index.
|
||
|
||
Example: If the baseVertexIndex for the sub-mesh is 5 and the triangle entry
|
||
is (4, 8, 7, 0), then the actual indices for the vertices are (4 + 5, 8 + 5, 7 + 5).
|
||
|
||
@b Flags
|
||
|
||
The flags entry indicates which edges are internal and which are external to
|
||
the sub-mesh. Internal edges connect to other triangles within the same sub-mesh.
|
||
External edges represent portals to other sub-meshes or the null region.
|
||
|
||
Each flag is stored in a 2-bit position. Where position 0 is the lowest 2-bits
|
||
and position 4 is the highest 2-bits:
|
||
|
||
<tt>
|
||
Position 0: Edge AB (>> 0)<br/>
|
||
Position 1: Edge BC (>> 2)<br/>
|
||
Position 2: Edge CA (>> 4)<br/>
|
||
Position 4: Unused<br/>
|
||
</tt>
|
||
|
||
Testing can be performed as follows:
|
||
|
||
@code
|
||
if (((flags >> 2) & 0x3) != 0)
|
||
{
|
||
// Edge BC is an external edge.
|
||
}
|
||
@endcode
|
||
|
||
@fn void rcSetCon(rcCompactSpan &s, int dir, int i)
|
||
@par
|
||
|
||
This function is used by the build process. It is rarely of use to end users.
|
||
|
||
@see #rcCompactHeightfield, #rcCompactSpan
|
||
|
||
@fn int rcGetCon(const rcCompactSpan &s, int dir)
|
||
@par
|
||
|
||
Can be used to locate neighbor spans in a compact heightfield. See the
|
||
#rcCompactHeightfield documentation for details on its use.
|
||
|
||
@see #rcCompactHeightfield, #rcCompactSpan
|
||
|
||
@fn int rcGetDirOffsetX(int dir)
|
||
@par
|
||
|
||
The value of @p dir will be automatically wrapped. So a value of 6 will be interpreted as 2.
|
||
|
||
See the #rcCompactHeightfield documentation for usage details.
|
||
|
||
@fn int rcGetDirOffsetY(int dir)
|
||
@par
|
||
|
||
The value of @p dir will be automatically wrapped. So a value of 6 will be interpreted as 2.
|
||
|
||
See the #rcCompactHeightfield documentation for usage details.
|
||
|
||
*/
|