Added option to add rotated Box obstacle to TileCache. (#278)
Very useful when you have a obstacle with a big difference in x to z ratio and that could be rotated (not aligned), like a wall.
This commit is contained in:
parent
46654531e4
commit
840c100639
@ -38,7 +38,8 @@ enum ObstacleState
|
|||||||
enum ObstacleType
|
enum ObstacleType
|
||||||
{
|
{
|
||||||
DT_OBSTACLE_CYLINDER,
|
DT_OBSTACLE_CYLINDER,
|
||||||
DT_OBSTACLE_BOX,
|
DT_OBSTACLE_BOX, // AABB
|
||||||
|
DT_OBSTACLE_ORIENTED_BOX, // OBB
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dtObstacleCylinder
|
struct dtObstacleCylinder
|
||||||
@ -54,6 +55,13 @@ struct dtObstacleBox
|
|||||||
float bmax[ 3 ];
|
float bmax[ 3 ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dtObstacleOrientedBox
|
||||||
|
{
|
||||||
|
float center[ 3 ];
|
||||||
|
float extents[ 3 ];
|
||||||
|
float rotAux[ 2 ]; //{ cos(0.5f*angle)*sin(-0.5f*angle); cos(0.5f*angle)*cos(0.5f*angle) - 0.5 }
|
||||||
|
};
|
||||||
|
|
||||||
static const int DT_MAX_TOUCHED_TILES = 8;
|
static const int DT_MAX_TOUCHED_TILES = 8;
|
||||||
struct dtTileCacheObstacle
|
struct dtTileCacheObstacle
|
||||||
{
|
{
|
||||||
@ -61,6 +69,7 @@ struct dtTileCacheObstacle
|
|||||||
{
|
{
|
||||||
dtObstacleCylinder cylinder;
|
dtObstacleCylinder cylinder;
|
||||||
dtObstacleBox box;
|
dtObstacleBox box;
|
||||||
|
dtObstacleOrientedBox orientedBox;
|
||||||
};
|
};
|
||||||
|
|
||||||
dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES];
|
dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES];
|
||||||
@ -130,8 +139,14 @@ public:
|
|||||||
|
|
||||||
dtStatus removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize);
|
dtStatus removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize);
|
||||||
|
|
||||||
|
// Cylinder obstacle.
|
||||||
dtStatus addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result);
|
dtStatus addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result);
|
||||||
|
|
||||||
|
// Aabb obstacle.
|
||||||
dtStatus addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result);
|
dtStatus addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result);
|
||||||
|
|
||||||
|
// Box obstacle: can be rotated in Y.
|
||||||
|
dtStatus addBoxObstacle(const float* center, const float* extents, const float yRadians, dtObstacleRef* result);
|
||||||
|
|
||||||
dtStatus removeObstacle(const dtObstacleRef ref);
|
dtStatus removeObstacle(const dtObstacleRef ref);
|
||||||
|
|
||||||
|
@ -130,6 +130,9 @@ dtStatus dtMarkCylinderArea(dtTileCacheLayer& layer, const float* orig, const fl
|
|||||||
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
||||||
const float* bmin, const float* bmax, const unsigned char areaId);
|
const float* bmin, const float* bmax, const unsigned char areaId);
|
||||||
|
|
||||||
|
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
||||||
|
const float* center, const float* extents, const float* rotAux, const unsigned char areaId);
|
||||||
|
|
||||||
dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
|
dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
|
||||||
dtTileCacheLayer& layer,
|
dtTileCacheLayer& layer,
|
||||||
const int walkableClimb);
|
const int walkableClimb);
|
||||||
|
@ -420,6 +420,45 @@ dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, dtObs
|
|||||||
return DT_SUCCESS;
|
return DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtStatus dtTileCache::addBoxObstacle(const float* center, const float* extents, const float yRadians, dtObstacleRef* result)
|
||||||
|
{
|
||||||
|
if (m_nreqs >= MAX_REQUESTS)
|
||||||
|
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
|
dtTileCacheObstacle* ob = 0;
|
||||||
|
if (m_nextFreeObstacle)
|
||||||
|
{
|
||||||
|
ob = m_nextFreeObstacle;
|
||||||
|
m_nextFreeObstacle = ob->next;
|
||||||
|
ob->next = 0;
|
||||||
|
}
|
||||||
|
if (!ob)
|
||||||
|
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
unsigned short salt = ob->salt;
|
||||||
|
memset(ob, 0, sizeof(dtTileCacheObstacle));
|
||||||
|
ob->salt = salt;
|
||||||
|
ob->state = DT_OBSTACLE_PROCESSING;
|
||||||
|
ob->type = DT_OBSTACLE_ORIENTED_BOX;
|
||||||
|
dtVcopy(ob->orientedBox.center, center);
|
||||||
|
dtVcopy(ob->orientedBox.extents, extents);
|
||||||
|
|
||||||
|
float coshalf= cosf(0.5f*yRadians);
|
||||||
|
float sinhalf = sinf(-0.5f*yRadians);
|
||||||
|
ob->orientedBox.rotAux[0] = coshalf*sinhalf;
|
||||||
|
ob->orientedBox.rotAux[1] = coshalf*coshalf - 0.5f;
|
||||||
|
|
||||||
|
ObstacleRequest* req = &m_reqs[m_nreqs++];
|
||||||
|
memset(req, 0, sizeof(ObstacleRequest));
|
||||||
|
req->action = REQUEST_ADD;
|
||||||
|
req->ref = getObstacleRef(ob);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
*result = req->ref;
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref)
|
dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref)
|
||||||
{
|
{
|
||||||
if (!ref)
|
if (!ref)
|
||||||
@ -650,7 +689,12 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
|||||||
else if (ob->type == DT_OBSTACLE_BOX)
|
else if (ob->type == DT_OBSTACLE_BOX)
|
||||||
{
|
{
|
||||||
dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
|
dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
|
||||||
ob->box.bmin, ob->box.bmax, 0);
|
ob->box.bmin, ob->box.bmax, 0);
|
||||||
|
}
|
||||||
|
else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
|
||||||
|
{
|
||||||
|
dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
|
||||||
|
ob->orientedBox.center, ob->orientedBox.extents, ob->orientedBox.rotAux, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -761,4 +805,16 @@ void dtTileCache::getObstacleBounds(const struct dtTileCacheObstacle* ob, float*
|
|||||||
dtVcopy(bmin, ob->box.bmin);
|
dtVcopy(bmin, ob->box.bmin);
|
||||||
dtVcopy(bmax, ob->box.bmax);
|
dtVcopy(bmax, ob->box.bmax);
|
||||||
}
|
}
|
||||||
|
else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
|
||||||
|
{
|
||||||
|
const dtObstacleOrientedBox &orientedBox = ob->orientedBox;
|
||||||
|
|
||||||
|
float maxr = 1.41f*dtMax(orientedBox.extents[0], orientedBox.extents[2]);
|
||||||
|
bmin[0] = orientedBox.center[0] - maxr;
|
||||||
|
bmax[0] = orientedBox.center[0] + maxr;
|
||||||
|
bmin[1] = orientedBox.center[1] - orientedBox.extents[1];
|
||||||
|
bmax[1] = orientedBox.center[1] + orientedBox.extents[1];
|
||||||
|
bmin[2] = orientedBox.center[2] - maxr;
|
||||||
|
bmax[2] = orientedBox.center[2] + maxr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2041,6 +2041,60 @@ dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float c
|
|||||||
return DT_SUCCESS;
|
return DT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
|
||||||
|
const float* center, const float* extents, const float* rotAux, const unsigned char areaId)
|
||||||
|
{
|
||||||
|
const int w = (int)layer.header->width;
|
||||||
|
const int h = (int)layer.header->height;
|
||||||
|
const float ics = 1.0f/cs;
|
||||||
|
const float ich = 1.0f/ch;
|
||||||
|
|
||||||
|
float cx = (center[0] - orig[0])*ics;
|
||||||
|
float cz = (center[2] - orig[2])*ics;
|
||||||
|
|
||||||
|
float maxr = 1.41f*dtMax(extents[0], extents[2]);
|
||||||
|
int minx = (int)floorf(cx - maxr*ics);
|
||||||
|
int maxx = (int)floorf(cx + maxr*ics);
|
||||||
|
int minz = (int)floorf(cz - maxr*ics);
|
||||||
|
int maxz = (int)floorf(cz + maxr*ics);
|
||||||
|
int miny = (int)floorf((center[1]-extents[1]-orig[1])*ich);
|
||||||
|
int maxy = (int)floorf((center[1]+extents[1]-orig[1])*ich);
|
||||||
|
|
||||||
|
if (maxx < 0) return DT_SUCCESS;
|
||||||
|
if (minx >= w) return DT_SUCCESS;
|
||||||
|
if (maxz < 0) return DT_SUCCESS;
|
||||||
|
if (minz >= h) return DT_SUCCESS;
|
||||||
|
|
||||||
|
if (minx < 0) minx = 0;
|
||||||
|
if (maxx >= w) maxx = w-1;
|
||||||
|
if (minz < 0) minz = 0;
|
||||||
|
if (maxz >= h) maxz = h-1;
|
||||||
|
|
||||||
|
float xhalf = extents[0]*ics + 0.5f;
|
||||||
|
float zhalf = extents[2]*ics + 0.5f;
|
||||||
|
|
||||||
|
for (int z = minz; z <= maxz; ++z)
|
||||||
|
{
|
||||||
|
for (int x = minx; x <= maxx; ++x)
|
||||||
|
{
|
||||||
|
float x2 = 2.0f*(float(x) - cx);
|
||||||
|
float z2 = 2.0f*(float(z) - cz);
|
||||||
|
float xrot = rotAux[1]*x2 + rotAux[0]*z2;
|
||||||
|
if (xrot > xhalf || xrot < -xhalf)
|
||||||
|
continue;
|
||||||
|
float zrot = rotAux[1]*z2 - rotAux[0]*x2;
|
||||||
|
if (zrot > zhalf || zrot < -zhalf)
|
||||||
|
continue;
|
||||||
|
const int y = layer.heights[x+z*w];
|
||||||
|
if (y < miny || y > maxy)
|
||||||
|
continue;
|
||||||
|
layer.areas[x+z*w] = areaId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
|
dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
|
||||||
dtTileCacheLayerHeader* header,
|
dtTileCacheLayerHeader* header,
|
||||||
const unsigned char* heights,
|
const unsigned char* heights,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user