**EDIT** Fixed the problem i had in this post, and i have changed the code to reflect the fix. It was due to the fact cfg.borderSize had not been initialised.
**EDIT #2** Code now takes a std::Vector of sceneNode pointers, converts all meshes attached to those nodes into a single recast tris and verts structure. It converts all verticies into world space relative to a parentSceneNode
This is how i have intergrated recast with Ogre, could someone have a look at it and make sure i am not doing any thing stupid! The problem is that my app crashes when it its run outside the visual studio enviroment which points to something reading past the end of an array but i have no way of finding where!
This code does work though, I will update it when i find a solution to the problem;
Create Nav Mesh (This is where my app crashes if not in the Visual Studio enviroment)
Code: Select all
//SceneNodeList is just a std::vector<Ogre::SceneNode*>, parentSceneNode is the reference sceneNode for converting vertices to world space
void AIManager::createNavigationMesh(SceneNodeList sceneNodeList, Ogre::SceneNode *parentSceneNode)
{
float bmin[3];
float bmax[3];
int ntris = 0; //number of total triangles
int *tris; //list of trinagles
float *verts; //list of verticies
int nverts = 0; //number of verticies
bool keepInterResults = false; // make sure you delete intermediate results
//config setup
//default values
float cellSize = 0.3f;
float cellHeight = 0.2f;
float agentHeight = 2.0f;
float agentRadius = 0.6f;
float agentMaxClimb = 0.2f;
float agentMaxSlope = 45.0f;
float regionMinSize = 50;
float regionMergeSize = 20;
float edgeMaxLen = 12.0f;
float edgeMaxError = 1.3f;
float vertsPerPoly = 6.0f;
float detailSampleDist = 6.0f;
float detailSampleMaxError = 1.0f;
//setup rc config structure
rcConfig cfg;
cfg.cs = cellSize;
cfg.ch = cellHeight;
cfg.walkableSlopeAngle = agentMaxSlope;
cfg.walkableHeight = (int)ceilf(agentHeight / cfg.ch);
cfg.walkableClimb = (int)ceilf(agentMaxClimb / cfg.ch);
cfg.walkableRadius = (int)ceilf(agentRadius / cfg.cs);
cfg.maxEdgeLen = (int)(edgeMaxLen / cellSize);
cfg.maxSimplificationError = edgeMaxError;
cfg.minRegionSize = (int)rcSqr(regionMinSize);
cfg.mergeRegionSize = (int)rcSqr(regionMergeSize);
cfg.maxVertsPerPoly = (int)vertsPerPoly;
cfg.detailSampleDist = detailSampleDist < 0.9f ? 0 : cellSize * detailSampleDist;
cfg.detailSampleMaxError = cellHeight * detailSampleMaxError;
cfg.borderSize = 0;
//get all vertices and triangles
// mesh data to retrieve
const int numNodes = sceneNodeList.size();
size_t *meshVertexCount = new size_t[numNodes];
size_t *meshIndexCount = new size_t[numNodes];
Ogre::Vector3 **meshVertices = new Ogre::Vector3*[numNodes];
Ogre::uint32 **meshIndices = new Ogre::uint32*[numNodes];
for (int i = 0 ; i < numNodes ; i++)
{
//TODO: Iterate through all attached objects and also check that attache object is an entity
Ogre::Entity *ent = (Ogre::Entity*)sceneNodeList[i]->getAttachedObject(0);
this->getMeshInformation(ent->getMesh(), meshVertexCount[i], meshVertices[i], meshIndexCount[i], meshIndices[i]);
//total number of verts
nverts += meshVertexCount[i];
//total number of indices
ntris += meshIndexCount[i];
}
verts = new float[nverts*3];// *3 as verts holds x,y,&z for each vert in the array
tris = new int[ntris];// tris in recast is really indicies like ogre
//convert index count into tri count
ntris = ntris/3; //although the tris array are indicies the ntris is actual number of triangles, ie indicies/3;
//set the reference node
Ogre::SceneNode *referenceNode;
if (parentSceneNode == 0)
{
referenceNode = SEAVis::Core::getSingleton().getSceneManager()->getRootSceneNode();
}
else
{
referenceNode = parentSceneNode;
}
//copy all meshes verticies into single buffer and transform to world space relative to parentNode
int vertsIndex = 0;
int prevVerticiesCount = 0;
int prevIndexCountTotal = 0;
for (int i = 0 ; i < sceneNodeList.size() ; i++)
{
//find the transform between the reference node and this node
Ogre::Matrix4 transform = referenceNode->_getFullTransform().inverse() *sceneNodeList[i]->_getFullTransform();
Ogre::Vector3 vertexPos;
for (int j = 0 ; j < meshVertexCount[i] ; j++)
{
vertexPos = transform*meshVertices[i][j];
verts[vertsIndex] = vertexPos.x;
verts[vertsIndex+1] = vertexPos.y;
verts[vertsIndex+2] = vertexPos.z;
vertsIndex+=3;
}
for (int j = 0 ; j < meshIndexCount[i] ; j++)
{
tris[prevIndexCountTotal+j] = meshIndices[i][j]+prevVerticiesCount;
}
prevIndexCountTotal += meshIndexCount[i];
prevVerticiesCount = meshVertexCount[i];
}
//delete tempory arrays
//TODO These probably could member varibles, this would increase performance slightly
for (int i = 0 ; i < numNodes ; i++)
{
delete [] meshVertices[i];
delete [] meshIndices[i];
}
delete [] meshVertices;
delete [] meshVertexCount;
delete [] meshIndices;
delete [] meshIndexCount;
// Set the area where the navigation will be build.
// Here the bounds of the input mesh are used, but the
// area could be specified by an user defined box, etc.
rcCalcBounds(verts, nverts, bmin, bmax);
vcopy(cfg.bmin, bmin);
vcopy(cfg.bmax, bmax);
rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
//................. The rest of the code is straight out of the recast demo
The getMeshInformation method is from this page in the wiki a few minor changes;
http://www.ogre3d.org/wiki/index.php/RetrieveVertexData
Draw NavMesh
Code: Select all
//displays a recast poly mesh and attaches it to parentSceneNode
void AIManager::displayNavMesh(rcPolyMesh *polyMesh, Ogre::SceneNode *parentSceneNode)
{
// Create a manual object
//TODO: Dont hardcode name!!!
Ogre::ManualObject *obj = SEAVis::Core::getSingleton().getSceneManager()->createManualObject("NavMesh");
obj->begin("NavMesh");
const int nvp = polyMesh->nvp;
const float cs = polyMesh->cs;
const float ch = polyMesh->ch;
const float* orig = polyMesh->bmin;
int nvt = 0; // triangle verts
for (int i = 0; i < polyMesh->npolys; ++i)
{
const unsigned short* p = &polyMesh->polys[i*nvp*2];
unsigned short vi[3];
for (int j = 2; j < nvp; ++j)
{
if (p[j] == 0xffff) break;
vi[0] = p[0];
vi[1] = p[j-1];
vi[2] = p[j];
for (int k = 0; k < 3; ++k)
{
const unsigned short* v = &polyMesh->verts[vi[k]*3];
const float x = orig[0] + v[0]*cs;
const float y = orig[1] + (v[1]+0.3)*ch; //+0.3 to set Nav mesh above Graphics mesh
const float z = orig[2] + v[2]*cs;
obj->position(x,y,z);
}
}
}
obj->end();
if (parentSceneNode == 0)
{
SEAVis::Core::getSingleton().getSceneManager()->getRootSceneNode()->attachObject(obj);
}
else
{
parentSceneNode->attachObject(obj);
}
}
As i said this code has a problem somewhere which leads to a crash, but i will update it when i fix it. Please feel free to use it to get yourself up and running
**EDIT** This is a first attempt piece of code, not my best code ever!! It can be optimized, having said that recastnavigation runs so fast its not needed yet!