recastnavigation添加多边形动态障碍物

      原始recastnavigation仅支持 圆柱体,box(AABB与OBB)三种形状的障碍物,当然这也是为了效率最大化,那么能否自定义扩展呢?其实也很简单,所以下面说一下具体修改方法,增加一个多边形的支持。

 

//1 增加一个多边形障碍物类型

enum ObstacleType
{
    DT_OBSTACLE_CYLINDER,
    DT_OBSTACLE_BOX, // AABB
    DT_OBSTACLE_ORIENTED_BOX, // OBB
    DT_POLYGON,
};

增加相应存储结构,最大64个顶点,高度我们固定(这个根据具体情况来)


struct dtObstaclePolygon
{
    unsigned short nvert;
    float verts[64 * 3];
    float height;
 
    static void bound(
        const unsigned short nvert, const float* verts,
        const float height,
        float* bmin, float* bmax) {
        bmin[0] = bmax[0] = verts[0];
        bmin[1] = bmax[1] = verts[1];
        bmin[2] = bmax[2] = verts[2];
        for (int i = 1; i < nvert; ++i) {
            if (bmin[0] > verts[i * 3]) {
                bmin[0] = verts[i * 3];
            }
            if (bmin[1] > verts[i * 3 + 1]) {
                bmin[1] = verts[i * 3 + 1];
            }
            if (bmin[2] > verts[i * 3 + 2]) {
                bmin[2] = verts[i * 3 + 2];
            }
            if (bmax[0] < verts[i * 3]) {
                bmax[0] = verts[i * 3];
            }
            if (bmax[1] < verts[i * 3 + 1]) {
                bmax[1] = verts[i * 3 + 1];
            }
            if (bmax[2] < verts[i * 3 + 2]) {
                bmax[2] = verts[i * 3 + 2];
            }
        }
        float avgh = (bmin[1] + bmax[1]) / 2;
        bmin[1] = dtMin(bmin[1], avgh - height / 2);
        bmax[1] = dtMax(bmax[1], avgh + height / 2);
    }
};
联合体增加相应数据(这里截取部分代码)

struct dtTileCacheObstacle
{
    union
    {
        dtObstacleCylinder cylinder;
        dtObstacleBox box;
        dtObstacleOrientedBox orientedBox;
                dtObstaclePolygon polygon;
    };
增加bound边框的获取逻辑,修改这个函数 void dtTileCache::getObstacleBounds(const struct dtTileCacheObstacle* ob, float* bmin, float* bmax) const


增加以下代码,获取bbox
else if(ob->type == DT_OBSTACLE_POLYGON){
        const dtObstaclePolygon& polygon = ob->polygon;
        dtObstaclePolygon::bound(polygon.nvert, polygon.verts, polygon.height, bmin, bmax);
    }


增加一个区域标记函数
dtStatus dtMarkPolygonArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
    const unsigned short nvert, const float* verts, const float height, const unsigned char areaId);


把这个函数放到dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh)的区域标记部分


else if (ob->type == DT_OBSTACLE_POLYGON) {
               
 dtMarkPolygonArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
                    ob->polygon.nvert, ob->polygon.verts, ob->polygon.height, 0);
           
 }  实现这个函数,将所有处于这个障碍物内的块的标记修改


这边多边形判定不需要自己实现了,源码有现成的dtPointInPolygon

dtStatus dtMarkPolygonArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
    const unsigned short nvert, const float* verts, const float height, const unsigned char areaId) {
 
    float bmin[3], bmax[3];
 
    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;
    // 计算当前grid坐标系下的边界
    dtObstaclePolygon::bound(nvert, verts, height, bmin, bmax);
    int minx = (int)dtMathFloorf((bmin[0] - orig[0])*ics);
    int miny = (int)dtMathFloorf((bmin[1] - orig[1])*ich);
    int minz = (int)dtMathFloorf((bmin[2] - orig[2])*ics);
    int maxx = (int)dtMathFloorf((bmax[0] - orig[0])*ics);
    int maxy = (int)dtMathFloorf((bmax[1] - orig[1])*ich);
    int maxz = (int)dtMathFloorf((bmax[2] - orig[2])*ics);
 
    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;
 
    for (int z = minz; z <= maxz; ++z)
    {
        for (int x = minx; x <= maxx; ++x)
        {
            const int y = layer.heights[x + z*w];
            if (y < miny || y > maxy)
                continue;
            const float pos[] = {
                x*cs + orig[0],
                y*ch + orig[1],
                z*cs + orig[2]
            };
            if (dtPointInPolygon(pos, verts, nvert))
                continue;
            layer.areas[x + z*w] = areaId;
        }
    }
 
    return DT_SUCCESS;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值