I added in the detour part to complete it.
You have to download recast detour library from GitHub. Recompile it, then link those lib to your project. Ignore the SDL errors.
https://github.com/memononen/recastnavigation
<<<How to use of recast_util.h>>>>
I should rename it to recast_detour_util.h. Since it included the detour navmesh function. I also add the return path function in there.
I leave this as an exercise for you.
recast_util.h
Code: Select all
#pragma once
#ifndef _RECAST_UTIL_H_
#define _RECAST_UTIL_H_
#include <iostream>
#include <vector>
#include <stdio.h>
#include <cstddef>
#include <math.h>
#include <irrlicht.h>
#include <Recast.h>
#include <DetourNavMeshQuery.h>
#include "SampleInterfaces.h"
#include <DetourNavMeshBuilder.h>
#include <DetourNavMesh.h>
#include "InputGeom.h"
#include "ChunkyTriMesh.h"
#ifndef RECAST_UTIL_PROPERTIES
#define RECAST_UTIL_PROPERTIES
#endif
/// Tool types.
enum SampleToolType
{
TOOL_NONE = 0,
TOOL_TILE_EDIT,
TOOL_TILE_HIGHLIGHT,
TOOL_TEMP_OBSTACLE,
TOOL_NAVMESH_TESTER,
TOOL_NAVMESH_PRUNE,
TOOL_OFFMESH_CONNECTION,
TOOL_CONVEX_VOLUME,
TOOL_CROWD,
MAX_TOOLS
};
/// These are just sample areas to use consistent values across the samples.
/// The use should specify these base on his needs.
enum SamplePolyAreas
{
SAMPLE_POLYAREA_GROUND,
SAMPLE_POLYAREA_WATER,
SAMPLE_POLYAREA_ROAD,
SAMPLE_POLYAREA_DOOR,
SAMPLE_POLYAREA_GRASS,
SAMPLE_POLYAREA_JUMP,
};
enum SamplePolyFlags
{
SAMPLE_POLYFLAGS_WALK = 0x01, // Ability to walk (ground, grass, road)
SAMPLE_POLYFLAGS_SWIM = 0x02, // Ability to swim (water).
SAMPLE_POLYFLAGS_DOOR = 0x04, // Ability to move through doors.
SAMPLE_POLYFLAGS_JUMP = 0x08, // Ability to jump.
SAMPLE_POLYFLAGS_DISABLED = 0x10, // Disabled polygon
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
};
class RecastUtilM
{
public:
RecastUtilM()/* : verts(0),
tris(0),
m_ctx(0),
m_keepInterResults(true),
m_totalBuildTimeMs(0),
m_triareas(0),
m_solid(0),
m_chf(0),
m_cset(0),
m_pmesh(0),
m_dmesh(0)*/
{
verts = 0;
tris = 0;
m_ctx = 0;
m_keepInterResults = true;
m_totalBuildTimeMs = 0;
m_triareas = 0;
m_solid = 0;
m_chf = 0;
m_cset = 0;
m_pmesh = 0;
m_dmesh = 0;
BuildContext *ctx;
m_ctx = new BuildContext();
//this->setContext(ctx);
this->resetCommonSettings();
};
~RecastUtilM()
{
cleanup();
};
private:
float* verts;
int* tris;
float m_cellSize;
float m_cellHeight;
float m_agentHeight;
float m_agentRadius;
float m_agentMaxClimb;
float m_agentMaxSlope;
float m_regionMinSize;
float m_regionMergeSize;
bool m_monotonePartitioning;
float m_edgeMaxLen;
float m_edgeMaxError;
float m_vertsPerPoly;
float m_detailSampleDist;
float m_detailSampleMaxError;
BuildContext* m_ctx;
bool m_keepInterResults;
float m_totalBuildTimeMs;
unsigned char* m_triareas;
rcHeightfield* m_solid;
rcCompactHeightfield* m_chf;
rcContourSet* m_cset;
rcPolyMesh* m_pmesh;
rcConfig m_cfg;
rcPolyMeshDetail* m_dmesh;
void cleanup();
protected:
InputGeom* m_geom;
dtNavMeshQuery* m_navQuery;
dtNavMesh* m_navMesh;
public:
void setContext(BuildContext* ctx) { m_ctx = ctx; }
//virtual ~RecastUtil();
bool handleBuild(irr::scene::IMeshBuffer* buffer);
void resetCommonSettings();
bool getMeshBufferData
(
irr::scene::IMeshBuffer* buffer,
std::vector<float>& verts, int& nverts,
std::vector<int>& tris, int& ntris
);
bool setupIrrSMeshFromRecastDetailMesh(irr::scene::SMesh* smesh);
void showHeightFieldInfo(const rcHeightfield& hf);
bool getMeshDataFromPolyMeshDetail
(
rcPolyMeshDetail* dmesh,
std::vector<float>& vertsOut, int& nvertsOut,
std::vector<int>& trisOut, int& ntrisOut
);
bool setMeshBufferData
(
irr::scene::SMeshBuffer& buffer,
const std::vector<float>& verts, int& nverts,
const std::vector<int>& tris, int& ntris
);
std::vector<irr::core::vector3df> returnPath(irr::core::vector3df pStart, irr::core::vector3df pEnd);
};
#endif // _RECAST_UTIL_H_
//recast_util.cpp
Code: Select all
#include "recast_util.h"
using namespace std;
using namespace irr;
using namespace irr::core;
void RecastUtilM::cleanup()
{
if (verts) { delete[] verts; verts = 0; }
if (tris) { delete[] tris; tris = 0; }
delete[] m_triareas;
m_triareas = 0;
rcFreeHeightField(m_solid);
m_solid = 0;
rcFreeCompactHeightfield(m_chf);
m_chf = 0;
rcFreeContourSet(m_cset);
m_cset = 0;
rcFreePolyMesh(m_pmesh);
m_pmesh = 0;
rcFreePolyMeshDetail(m_dmesh);
m_dmesh = 0;
//dtFreeNavMesh(m_navMesh);
//m_navMesh = 0;
//dtFreeNavMeshQuery(m_navQuery);
//m_navQuery = 0;
}
bool RecastUtilM::handleBuild(scene::IMeshBuffer* buffer)
{
cleanup();
std::vector<float> vs;
std::vector<int> ts;
int nverts;
int ntris;
if (!this->getMeshBufferData(buffer, vs, nverts, ts, ntris))
{
printf("getMeshBufferData() failed!\n");
return false;
}
// populate verts and tris:
verts = new float[nverts];
for (int n = 0; n < nverts; ++n)
{
verts[n] = vs[n];
//printf("verts[%i]=%g\n", n, verts[n]);
}
tris = new int[ntris * 3];
for (int n = 0; n < ntris; ++n)
{
tris[n * 3] = ts[n * 3];
tris[n * 3 + 1] = ts[n * 3 + 1];
tris[n * 3 + 2] = ts[n * 3 + 2];
//printf("tris[%i]=(%i,%i,%i)\n", n, tris[n*3], tris[n*3+1], tris[n*3+2]);
}
printf("vs.size()=%i,nverts=%i\n", vs.size(), nverts);
printf("ts.size()=%i,ntris=%i\n", ts.size(), ntris);
float bmin[3];
float bmax[3];
//rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax)
rcCalcBounds(verts, nverts / 3, bmin, bmax);
//
// Step 1. Initialize build config.
//
// Init build configuration from GUI
memset(&m_cfg, 0, sizeof(m_cfg));
m_cfg.cs = m_cellSize;
m_cfg.ch = m_cellHeight;
m_cfg.walkableSlopeAngle = m_agentMaxSlope;
m_cfg.walkableHeight = (int)ceilf(m_agentHeight / m_cfg.ch);
m_cfg.walkableClimb = (int)floorf(m_agentMaxClimb / m_cfg.ch);
m_cfg.walkableRadius = (int)ceilf(m_agentRadius / m_cfg.cs);
m_cfg.maxEdgeLen = (int)(m_edgeMaxLen / m_cellSize);
m_cfg.maxSimplificationError = m_edgeMaxError;
m_cfg.minRegionArea = (int)rcSqr(m_regionMinSize); // Note: area = size*size
m_cfg.mergeRegionArea = (int)rcSqr(m_regionMergeSize); // Note: area = size*size
m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
// 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.
rcVcopy(m_cfg.bmin, bmin);
rcVcopy(m_cfg.bmax, bmax);
rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);
// Reset build times gathering.
m_ctx->resetTimers();
// Start the build process.
m_ctx->startTimer(RC_TIMER_TOTAL);
m_ctx->log(RC_LOG_PROGRESS, "Building navigation:");
m_ctx->log(RC_LOG_PROGRESS, " - %d x %d cells", m_cfg.width, m_cfg.height);
m_ctx->log(RC_LOG_PROGRESS, " - %.1fK verts, %.1fK tris", nverts / 1000.0f, ntris / 1000.0f);
//
// Step 2. Rasterize input polygon soup.
//
// Allocate voxel heightfield where we rasterize our input data to.
m_solid = rcAllocHeightfield();
if (!m_solid)
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
return false;
}
if (!rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
return false;
}
// Allocate array that can hold triangle area types.
// If you have multiple meshes you need to process, allocate
// and array which can hold the max number of triangles you need to process.
m_triareas = new unsigned char[ntris];
if (!m_triareas)
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (%d).", ntris);
return false;
}
// Find triangles which are walkable based on their slope and rasterize them.
// If your input data is multiple meshes, you can transform them here, calculate
// the are type for each of the meshes and rasterize them.
memset(m_triareas, 0, ntris*sizeof(unsigned char));
rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas);
rcRasterizeTriangles(m_ctx, verts, nverts, tris, m_triareas, ntris, *m_solid, m_cfg.walkableClimb);
this->showHeightFieldInfo(*m_solid); //<-----------------------------------------------------------------------------------------
if (!m_keepInterResults)
{
delete[] m_triareas;
m_triareas = 0;
}
//
// Step 3. Filter walkables surfaces.
//
// Once all geoemtry is rasterized, we do initial pass of filtering to
// remove unwanted overhangs caused by the conservative rasterization
// as well as filter spans where the character cannot possibly stand.
rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, *m_solid);
rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid);
rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, *m_solid);
//
// Step 4. Partition walkable surface to simple regions.
//
// Compact the heightfield so that it is faster to handle from now on.
// This will result more cache coherent data as well as the neighbours
// between walkable cells will be calculated.
m_chf = rcAllocCompactHeightfield();
if (!m_chf)
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
return false;
}
if (!rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
return false;
}
if (!m_keepInterResults)
{
rcFreeHeightField(m_solid);
m_solid = 0;
}
// Erode the walkable area by agent radius.
if (!rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, *m_chf))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not erode.");
return false;
}
// (Optional) Mark areas.
//const ConvexVolume* vols = m_geom->getConvexVolumes();
//for (int i = 0; i < m_geom->getConvexVolumeCount(); ++i)
//rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (unsigned char)vols[i].area, *m_chf);
if (m_monotonePartitioning)
{
// Partition the walkable surface into simple regions without holes.
// Monotone partitioning does not need distancefield.
if (!rcBuildRegionsMonotone(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions.");
return false;
}
}
else
{
// Prepare for region partitioning, by calculating distance field along the walkable surface.
if (!rcBuildDistanceField(m_ctx, *m_chf))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
return false;
}
// Partition the walkable surface into simple regions without holes.
if (!rcBuildRegions(m_ctx, *m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build regions.");
return false;
}
}
//
// Step 5. Trace and simplify region contours.
//
// Create contours.
m_cset = rcAllocContourSet();
if (!m_cset)
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
return false;
}
if (!rcBuildContours(m_ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not create contours.");
return false;
}
printf("m_cset->nconts=%i\n", m_cset->nconts);
//
// Step 6. Build polygons mesh from contours.
//
// Build polygon navmesh from the contours.
m_pmesh = rcAllocPolyMesh();
if (!m_pmesh)
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
return false;
}
if (!rcBuildPolyMesh(m_ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
return false;
}
//
// Step 7. Create detail mesh which allows to access approximate height on each polygon.
//
m_dmesh = rcAllocPolyMeshDetail();
if (!m_dmesh)
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
return false;
}
if (!rcBuildPolyMeshDetail(m_ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh))
{
m_ctx->log(RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
return false;
}
if (!m_keepInterResults)
{
rcFreeCompactHeightfield(m_chf);
m_chf = 0;
rcFreeContourSet(m_cset);
m_cset = 0;
}
// At this point the navigation mesh data is ready, you can access it from m_pmesh.
// See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.
//
// (Optional) Step 8. Create Detour data from Recast poly mesh.
//
// ...
//
// (Optional) Step 8. Create Detour data from Recast poly mesh.
//
// The GUI may allow more max points per polygon than Detour can handle.
// Only build the detour navmesh if we do not exceed the limit.
if (m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON)
{
unsigned char* navData = 0;
int navDataSize = 0;
// Update poly flags from areas.
for (int i = 0; i < m_pmesh->npolys; ++i)
{
if (m_pmesh->areas[i] == RC_WALKABLE_AREA)
m_pmesh->areas[i] = SAMPLE_POLYAREA_GROUND;
if (m_pmesh->areas[i] == SAMPLE_POLYAREA_GROUND ||
m_pmesh->areas[i] == SAMPLE_POLYAREA_GRASS ||
m_pmesh->areas[i] == SAMPLE_POLYAREA_ROAD)
{
m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK;
}
else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_WATER)
{
m_pmesh->flags[i] = SAMPLE_POLYFLAGS_SWIM;
}
else if (m_pmesh->areas[i] == SAMPLE_POLYAREA_DOOR)
{
m_pmesh->flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR;
}
}
// InputGeom* geom = new InputGeom;
//m_geom->raycastMesh()
dtNavMeshCreateParams params;
memset(¶ms, 0, sizeof(params));
params.verts = m_pmesh->verts;
params.vertCount = m_pmesh->nverts;
params.polys = m_pmesh->polys;
params.polyAreas = m_pmesh->areas;
params.polyFlags = m_pmesh->flags;
params.polyCount = m_pmesh->npolys;
params.nvp = m_pmesh->nvp;
params.detailMeshes = m_dmesh->meshes;
params.detailVerts = m_dmesh->verts;
params.detailVertsCount = m_dmesh->nverts;
params.detailTris = m_dmesh->tris;
params.detailTriCount = m_dmesh->ntris;
/*params.offMeshConVerts = m_geom->getOffMeshConnectionVerts();
params.offMeshConRad = m_geom->getOffMeshConnectionRads();
params.offMeshConDir = m_geom->getOffMeshConnectionDirs();
params.offMeshConAreas = m_geom->getOffMeshConnectionAreas();
params.offMeshConFlags = m_geom->getOffMeshConnectionFlags();
params.offMeshConUserID = m_geom->getOffMeshConnectionId();
params.offMeshConCount = m_geom->getOffMeshConnectionCount();*/
params.offMeshConAreas = 0;
params.offMeshConCount = 0;
params.offMeshConDir = 0;
params.offMeshConFlags = 0;
params.offMeshConRad = 0;
params.offMeshConUserID = 0;
params.offMeshConVerts = 0;
params.walkableHeight = m_agentHeight;
params.walkableRadius = m_agentRadius;
params.walkableClimb = m_agentMaxClimb;
rcVcopy(params.bmin, m_pmesh->bmin);
rcVcopy(params.bmax, m_pmesh->bmax);
params.cs = m_cfg.cs;
params.ch = m_cfg.ch;
params.buildBvTree = true;
if (!dtCreateNavMeshData(¶ms, &navData, &navDataSize))
{
m_ctx->log(RC_LOG_ERROR, "Could not build Detour navmesh.");
return false;
}
m_navMesh = dtAllocNavMesh();
if (!m_navMesh)
{
dtFree(navData);
m_ctx->log(RC_LOG_ERROR, "Could not create Detour navmesh");
return false;
}
dtStatus status;
status = m_navMesh->init(navData, navDataSize, DT_TILE_FREE_DATA);
if (dtStatusFailed(status))
{
dtFree(navData);
m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh");
return false;
}
m_navQuery = dtAllocNavMeshQuery();
status = m_navQuery->init(m_navMesh, 2048);
if (dtStatusFailed(status))
{
m_ctx->log(RC_LOG_ERROR, "Could not init Detour navmesh query");
return false;
}
}
m_ctx->stopTimer(RC_TIMER_TOTAL);
// Show performance stats.
duLogBuildTimes(*m_ctx, m_ctx->getAccumulatedTime(RC_TIMER_TOTAL));
m_ctx->log(RC_LOG_PROGRESS, ">> Polymesh: %d vertices %d polygons", m_pmesh->nverts, m_pmesh->npolys);
m_totalBuildTimeMs = m_ctx->getAccumulatedTime(RC_TIMER_TOTAL) / 1000.0f;
// irr part:
printf("RC_LOG_PROGRESS >> Polymesh: %d vertices %d polygons\n", m_pmesh->nverts, m_pmesh->npolys);
return true;
}
void RecastUtilM::resetCommonSettings()
{
m_cellSize = 4.0f; // 0.3f; // 0.3f;
m_cellHeight = 0.2f;
m_agentHeight = 2.0f;
m_agentRadius = 0.6f;
m_agentMaxClimb = 0.9f;
m_agentMaxSlope = 45.0f;
m_regionMinSize = 8;
m_regionMergeSize = 20;
m_monotonePartitioning = false;
m_edgeMaxLen = 12.0f;
m_edgeMaxError = 1.3f;
m_vertsPerPoly = 6.0f;
m_detailSampleDist = 6.0f;
m_detailSampleMaxError = 1.0f;
}
bool RecastUtilM::getMeshBufferData
(
scene::IMeshBuffer* buffer,
std::vector<float>& verts, int& nverts,
std::vector<int>& tris, int& ntris
)
{
nverts = buffer->getVertexCount() * 3;
printf("nverts=%i\n", nverts);
ntris = buffer->getIndexCount() / 3;
printf("ntris=%i\n", ntris);
if ((nverts <= 0) || (ntris <= 0))
{
printf("(nverts <= 0) || (ntris <= 0)\n");
return false;
}
for (int i = 0; i < int(buffer->getVertexCount()); ++i)
{
core::vector3df pos = buffer->getPosition(i);
verts.push_back(pos.X);
verts.push_back(pos.Y);
verts.push_back(pos.Z);
}
u16* indices = buffer->getIndices();
//for (int i = 0; i < int(buffer.Indices.size()); ++i)
for (int i = 0; i < ntris; ++i)
{
// some verts may contain nan (invalid values)??:
/***
bool ok = true;
for (int j = 0; j < 3; ++j)
{
if (isnan(verts[buffer.Indices[i*3+j]]))
{
ok = false;
break;
}
}
if (!ok)
continue;
***/
tris.push_back(indices[i * 3]);
tris.push_back(indices[i * 3 + 1]);
tris.push_back(indices[i * 3 + 2]);
}
ntris = int(tris.size() / 3);
// replace nan with 0 in verts:
//for (int n = 0; n < int(verts.size()); ++n)
//if (isnan(verts[n]))
//verts[n] = 0.0f;
return true;
}
bool RecastUtilM::setupIrrSMeshFromRecastDetailMesh(scene::SMesh* smesh)
{
rcPolyMeshDetail* dmesh = m_dmesh;
if ((!smesh) || (!dmesh))
return false;
scene::SMeshBuffer* buffer = new scene::SMeshBuffer();
std::vector<float> vertsOut;
int nvertsOut = 0;
std::vector<int> trisOut;
int ntrisOut = 0;
bool ok = getMeshDataFromPolyMeshDetail
(
dmesh,
vertsOut, nvertsOut,
trisOut, ntrisOut
);
if (!ok)
{
printf("setupSMesh(): getMeshDataFromPolyMeshDetail() failed!\n");
buffer->drop();
return false;
}
printf("setupSMesh(): vertsOut.size()=%i\n", vertsOut.size());
ok = setMeshBufferData// std::vector version!
(
*buffer, vertsOut, nvertsOut, trisOut, ntrisOut
);
if (!ok)
{
printf("setupSMesh(): setMeshBufferData() failed!\n");
buffer->drop();
return false;
}
// this is important:
// if not done, scene may disappear sometimes!
// recalculate bounding box
for (u32 n = 0; n < buffer->getVertexCount(); ++n)
{
buffer->BoundingBox.addInternalPoint(buffer->Vertices[n].Pos);
}
smesh->addMeshBuffer(buffer);
smesh->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX_AND_INDEX);
smesh->recalculateBoundingBox();
buffer->drop();
return true;
}
void RecastUtilM::showHeightFieldInfo(const rcHeightfield& hf)
{
int w = hf.width;
int h = hf.height;
const float* bmin = hf.bmin;
const float* bmax = hf.bmax;
float cs = hf.cs;
float ch = hf.ch;
printf ( "rcHeightfield hf: w=%i,h=%i,bmin=(%f,%f,%f),bmax=(%f,%f,%f),cs=%f,ch=%f\n", w, h, bmin[0], bmin[1], bmin[2], bmax[0], bmax[1], bmax[2], cs, ch);
}
more for recast_util.cpp...
Code: Select all
bool RecastUtilM::getMeshDataFromPolyMeshDetail ( rcPolyMeshDetail* dmesh, std::vector<float>& vertsOut, int& nvertsOut, std::vector<int>& trisOut, int& ntrisOut)
{
printf("getMeshDataFromPolyMeshDetail(): dmesh->nmeshes=%i\n", dmesh->nmeshes);
if (dmesh->nmeshes == 0)
{
printf("getMeshDataFromPolyMeshDetail(): dmesh->nmeshes == 0\n");
return false;
}
nvertsOut = dmesh->nverts * 3;
printf("getMeshDataFromPolyMeshDetail: nvertsOut=%i\n", nvertsOut);
ntrisOut = dmesh->ntris;
printf("getMeshDataFromPolyMeshDetail: ntrisOut=%i\n", ntrisOut);
//const unsigned char* tris = dmesh->tris;
const float* verts = dmesh->verts;
for (int n = 0; n < nvertsOut; ++n)
{
//printf("getMeshDataFromPolyMeshDetail: tris[n*4+k]=%i\n", tris[n*4+k]);
vertsOut.push_back(verts[n]);
}
//FIXME:
int tri_offset = 0;
int old_nverts = 0;
for (int p = 0; p < dmesh->nmeshes; ++p)
{
unsigned int* m = &(dmesh->meshes[p * 4]);
const unsigned short bverts = m[0]; // `b' means "beginning of"!!
const unsigned short nverts = m[1];
const unsigned short btris = m[2];
const unsigned short ntris = m[3];
//const float* verts = &(dmesh->verts[bverts*3]);
const unsigned char* tris = &(dmesh->tris[btris * 4]);
//printf("meshnum=%i, bverts=%i, btris=%i\n", p, bverts, btris);
//ntrisOut += int(ntris);
tri_offset += old_nverts;
for (int n = 0; n < ntris; ++n)
{
for (int k = 0; k < 3; ++k)
{
int tri = tris[n * 4 + k] + tri_offset;
trisOut.push_back(tri);
//printf("getMeshDataFromPolyMeshDetail: tri=%i, index=%i\n", n, tri);
//vertsOut.push_back(verts[tri*3 + 0]);
//vertsOut.push_back(verts[tri*3 + 1]);
//vertsOut.push_back(verts[tri*3 + 2]);
}
}
old_nverts = nverts;
}
// printf("getMeshDataFromPolyMeshDetail(): vertsOut.size()=%i\n", vertsOut.size());
return true;
}
bool RecastUtilM::setMeshBufferData ( scene::SMeshBuffer& buffer, const std::vector<float>& verts, int& nverts, const std::vector<int>& tris, int& ntris)
{
//TODO:
// err handling:
if (verts.empty() || tris.empty())
{
return false;
}
buffer.Vertices.set_used(nverts / 3);
buffer.Indices.set_used(ntris * 3); // ntris triangles!
//video::SColor color(255, 255, 255, 255);
//video::SColor color(128, 255, 255, 255);
//S3DVertex => pos, normal, color, texcoords
for (int i = 0; i < nverts; i += 3)
{
float x = verts[i];
float y = verts[i + 1];
float z = verts[i + 2];
buffer.Vertices[i / 3] = video::S3DVertex
(
x, y, z,
0.0f, 1.0f, 0.0f,
//0.0f, 0.0f, 0.0f,
0x80FF0000,
//0xFFFFFFFF,
0.0f, 0.0f
);
}
for (int i = 0; i < ntris * 3; ++i)
{
int index = tris[i];
buffer.Indices[i] = index;
}
buffer.getMaterial().Lighting = false;
buffer.getMaterial().BackfaceCulling = false;
buffer.getMaterial().Wireframe = true;
buffer.getMaterial().Thickness = 2.0f;
//buffer.getMaterial().MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
buffer.getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
//buffer.getMaterial().MaterialType = video::EMT_SOLID;
buffer.recalculateBoundingBox();
return true;
}
//Detour stuff
vector<irr::core::vector3df> RecastUtilM::returnPath(core::vector3df pStart, core::vector3df pEnd)
{
std::vector<irr::core::vector3df> lstPoints;
if (m_navQuery)
{
if (m_navMesh == 0)
{
return lstPoints;
}
dtQueryFilter m_filter;
dtPolyRef m_startRef;
dtPolyRef m_endRef;
const int MAX_POLYS = 256;
dtPolyRef m_polys[MAX_POLYS];
dtPolyRef returnedPath[MAX_POLYS];
float m_straightPath[MAX_POLYS * 3];
int numStraightPaths;
float m_spos[3] = { pStart.X, pStart.Y, pStart.Z };
float m_epos[3] = { pEnd.X, pEnd.Y, pEnd.Z };
float m_polyPickExt[3];
m_polyPickExt[0] = 2;
m_polyPickExt[1] = 4;
m_polyPickExt[2] = 2;
m_navQuery->findNearestPoly(m_spos, m_polyPickExt, &m_filter, &m_startRef, 0);
if (m_startRef == 0)
{
return lstPoints;
}
m_navQuery->findNearestPoly(m_epos, m_polyPickExt, &m_filter, &m_endRef, 0);
if (m_endRef == 0)
{
return lstPoints;
}
dtStatus findStatus = DT_FAILURE;
int pathCount;
findStatus = m_navQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, returnedPath, &pathCount, MAX_POLYS);
if (pathCount > 0)
{
findStatus = m_navQuery->findStraightPath(m_spos, m_epos, returnedPath,
pathCount, m_straightPath, 0, 0, &numStraightPaths, MAX_POLYS);
for (int i = 0; i < numStraightPaths; ++i)
{
vector3df cpos(m_straightPath[i * 3], m_straightPath[i * 3 + 1] + 0.25,
m_straightPath[i * 3 + 2]);
lstPoints.push_back(cpos);
//path->AddNode(node);
}
}
}
return lstPoints;
}
RecastUtilM::returnPath(core::vector3df pStart, core::vector3df pEnd)
To use it:
Code: Select all
irr::scene::IAnimatedMesh *terrain_model = smgr->addHillPlaneMesh("groundPlane", // Name of the scenenode
tileSize, // Tile size
tileCount, // Tile count
0, // Material
20.0f, // Hill height
core::dimension2d<f32>(0.0f, 1.0f), // countHills
core::dimension2d<f32>(1.0f, 1.0f)); ;// textureRepeatCount
terrain_node = smgr->addAnimatedMeshSceneNode(terrain_model);
scene::IMeshBuffer *terbuffer = terrain_node->getMesh()->getMeshBuffer(0);
if (terbuffer)
{
recast = new RecastUtilM();
if (recast->handleBuild(terbuffer))
{
scene::SMesh* smesh = new scene::SMesh();
if (!recast->setupIrrSMeshFromRecastDetailMesh(smesh))
{
printf("recast->setupIrrSMeshFromRecastDetailMesh(smesh): FAILED!\n");
}
else
{
scene::ISceneNode *naviNode = smgr->addOctTreeSceneNode(smesh);
naviNode->setName("Terrain");
naviNode->setDebugDataVisible(scene::EDS_MESH_WIRE_OVERLAY);
}
smesh->drop();
}
}
//On your event input positions
vector<irr::core::vector3df> lstPoints = recast->returnPath(vector3df_Start, vector3df_End);
Note: The setting I used below is for a large mesh. Usually the setting for m_cellSize is 0.3f instead of 4.0f.
void RecastUtilM::resetCommonSettings()
{
m_cellSize = 4.0f; // 0.3f;
m_cellHeight = 0.2f;
m_agentHeight = 2.0f;
m_agentRadius = 0.6f;
m_agentMaxClimb = 0.9f;
m_agentMaxSlope = 45.0f;
m_regionMinSize = 8;
m_regionMergeSize = 20;
m_monotonePartitioning = false;
m_edgeMaxLen = 12.0f;
m_edgeMaxError = 1.3f;
m_vertsPerPoly = 6.0f;
m_detailSampleDist = 6.0f;
m_detailSampleMaxError = 1.0f;
}
Images
Routing 5 ninjas.
Path planning 600 animated ninjas.
On both images link red triangulation is the navmesh, blue line is the path generated.
**Updated to make code display. It turns out that this forum limited the length for the code tag. So I have cut the C++ soure file into two junks as above.
Goodluck!