Recast + Detour - Connecting tiles menu

User Tag List

Results 1 to 13 of 13
  1. #1
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Recast + Detour - Connecting tiles

    All-

    Sorry for all the general posts lately, but I've been making a lot of progress in the pathing space (good fun on OS X ). I can load my nav meshes fine into RecastDemo, and into my own application. The issue i'm running into is I can't generate a path across tiles. If it's within one tile, it's fine.

    Anyone have any suggestions? I've seen many topics on the same problem, but didn't really see a solution. I have tried most things, like when generating the tiles, include all of the tiles around it (in case of walls, cliffs, etc...)

    Anyone have any ideas on how I can fix my generation? Here are my parameters:

    Code:
    #define m_cellSize (1.0f / 3.0f)
    #define m_cellHeight 0.3f
    
    #define m_agentHeight 1.652778f
    #define m_agentRadius 0.35f
    
    #define m_agentMaxClimb 1.0f
    #define m_agentMaxSlope 50.0f
    
    #define m_regionMinSize 8       // 20
    #define m_regionMergeSize 20    // 40
    
    #define m_edgeMaxLen 12.0f
    #define m_edgeMaxError 1.0f
    
    #define m_vertsPerPoly 6.0f
    #define m_detailSampleDist 3.0f
    #define m_detailSampleMaxError 1.0f
    
    #define m_tileSize 1600.0f
    
    #define m_keepInterResults false
    
    #define m_monotonePartitioning false
    And here is how I'm actually generating it (basically straight out of RecastDemo):
    Code:
    struct ObjData
    {
    	Vertices_t vertices;
    	Indices32_t indices;
    	Normals_t normals;
        AdtCoords_t *coords;
    	
    	void clear(){
    		vertices.clear();
    		indices.clear();
    		normals.clear();
    	}
    };
    // objData = our tile and the tiles bordering it
    // obj = our tile
    - (void)generateMeshesWithObj:(ObjData*)objData toDirectory:(NSString*)directory andX:(int)tx andY:(int)ty andTile:(ObjData*)obj{
        
        // create our mesh loader basd on all this data (3x3 based on the tile we want the mesh for)
    	rcMeshLoaderObj *loader = CreateMeshLoader(objData);
        
        if ( !loader ){
            NSLog(@"Unable to create loader for (%d, %d)", tx, ty);
            return;
        }
        
    	InputGeom *geom = new InputGeom();
    	if ( !geom->loadMesh(0, loader) ){
            NSLog(@"Unable to load ObjData");
    		return;
    	}
        
        if ( !geom || !geom->getMesh() || !geom->getChunkyMesh() ){
    		NSLog(@"buildNavigation: Input mesh is not specified.");
    		return;
    	}
        
        const float *bmin = geom->getMeshBoundsMin();
    	const float *bmax = geom->getMeshBoundsMax();
    	const float* verts = geom->getMesh()->getVerts();
    	const int nverts = geom->getMesh()->getVertCount();
    	const rcChunkyTriMesh* chunkyMesh = geom->getChunkyMesh();
        
    	rcConfig m_cfg;	
    	// 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.tileSize = (int)m_tileSize;
    	m_cfg.borderSize = m_cfg.walkableRadius + 3; // Reserve enough padding.
    	m_cfg.width = m_cfg.tileSize + m_cfg.borderSize*2;
    	m_cfg.height = m_cfg.tileSize + m_cfg.borderSize*2;
    	m_cfg.detailSampleDist = m_detailSampleDist < 0.9f ? 0 : m_cellSize * m_detailSampleDist;
    	m_cfg.detailSampleMaxError = m_cellHeight * m_detailSampleMaxError;
    	
        rcVcopy(m_cfg.bmin, bmin);
    	rcVcopy(m_cfg.bmax, bmax);
    	m_cfg.bmin[0] -= m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmin[2] -= m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmax[0] += m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmax[2] += m_cfg.borderSize*m_cfg.cs;
        
        NSLog(@"Overall...");
        NSLog(@" min: {%0.2f, %0.2f, %0.2f}", bmin[0], bmin[1], bmin[2]);
        NSLog(@" max: {%0.2f, %0.2f, %0.2f}", bmax[0], bmax[1], bmax[2]);
        
        rcContext *ctx = NULL;
        NSDate *start = [NSDate date];
        
        // clean up from previous run
        if ( ctx ){
            delete ctx;
        }
        
        // we only care about the coords for this tile, so lets set our bounds correctly!
        NSLog(@"(%d, %d) Generating mesh...", tx, ty);
        
        // ** Get our bounds for the tile we care about
        rcMeshLoaderObj *loader2 = CreateMeshLoader(obj);
    	InputGeom *geomTile = new InputGeom();
    	if ( !geomTile->loadMesh(0, loader2) ){
            NSLog(@"Unable to load ObjData2(%d, %d)", tx, ty);
    		return;
    	}
        
        if ( !geomTile || !geomTile->getMesh() || !geomTile->getChunkyMesh() ){
    		NSLog(@"buildNavigation: Input mesh is not specified.2(%d, %d)", tx, ty);
    		return;
    	}
        const float *bminTile = geomTile->getMeshBoundsMin();
    	const float *bmaxTile = geomTile->getMeshBoundsMax();
        
        m_cfg.bmin[0] = bminTile[0];
        m_cfg.bmin[2] = bminTile[2];
        m_cfg.bmax[0] = bmaxTile[0];
        m_cfg.bmax[2] = bmaxTile[2];
        
        // we want to go over the tile's edge a bit!
        /*m_cfg.bmin[0] -= m_cfg.borderSize*m_cfg.cs;
        m_cfg.bmin[2] -= m_cfg.borderSize*m_cfg.cs;
        m_cfg.bmax[0] += m_cfg.borderSize*m_cfg.cs;
        m_cfg.bmax[2] += m_cfg.borderSize*m_cfg.cs;*/
        // ** End - Get our bounds
        
        NSLog(@" min: {%0.2f, %0.2f, %0.2f}", bminTile[0], bminTile[1], bminTile[2]);
        NSLog(@" max: {%0.2f, %0.2f, %0.2f}", bmaxTile[0], bmaxTile[1], bmaxTile[2]);
        
        // set up our context
        ctx = new rcContext();
        ctx->resetTimers();
        ctx->startTimer(RC_TIMER_TOTAL);
        
        // Allocate voxel heightfield where we rasterize our input data to.
        rcHeightfield *m_solid = rcAllocHeightfield();
        if ( !m_solid ){
            NSLog(@"buildNavigation: Out of memory 'solid'.");
            return;
        }
        if ( !rcCreateHeightfield(ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch) ){
            NSLog(@"buildNavigation: Could not create solid heightfield.");
            return;
        }
        
        // Allocate array that can hold triangle flags.
        // If you have multiple meshes you need to process, allocate
        // and array which can hold the max number of triangles you need to process.
        unsigned char *m_triareas = new unsigned char[chunkyMesh->maxTrisPerChunk];
        if ( !m_triareas ){
            NSLog(@"buildNavigation: Out of memory 'm_triareas' (%d).", chunkyMesh->maxTrisPerChunk);
            return;
        }
        
        float tbmin[2], tbmax[2];
        tbmin[0] = m_cfg.bmin[0];
        tbmin[1] = m_cfg.bmin[2];
        tbmax[0] = m_cfg.bmax[0];
        tbmax[1] = m_cfg.bmax[2];
        int cid[10000];// TODO: Make grow when returning too many items.
        const int ncid = rcGetChunksOverlappingRect(chunkyMesh, tbmin, tbmax, cid, 10000);
        if ( !ncid ){
            NSLog(@"ncid error");
            return;
        }
        
        int m_tileTriCount = 0;
        
        for ( int i = 0; i < ncid; ++i ){
            const rcChunkyTriMeshNode& node = chunkyMesh->nodes[cid[i]];
            const int* tris = &chunkyMesh->tris[node.i*3];
            const int ntris = node.n;
            
            m_tileTriCount += ntris;
            
            memset(m_triareas, 0, ntris*sizeof(unsigned char));
            rcMarkWalkableTriangles( ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas );
            
            rcRasterizeTriangles( ctx, verts, nverts, tris, m_triareas, ntris, *m_solid, m_cfg.walkableClimb );
        }
        
        if ( !m_keepInterResults ){
            delete [] m_triareas;
            m_triareas = 0;
        }
        
        // Once all geometry 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(ctx, m_cfg.walkableClimb, *m_solid);
        rcFilterLedgeSpans(ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid);
        rcFilterWalkableLowHeightSpans(ctx, m_cfg.walkableHeight, *m_solid);
        
        // 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.
        rcCompactHeightfield *m_chf = rcAllocCompactHeightfield();
        if ( !m_chf ){
            NSLog(@"buildNavigation: Out of memory 'chf'.");
            return;
        }
        
        if ( !rcBuildCompactHeightfield(ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, *m_solid, *m_chf) ){
            NSLog(@"buildNavigation: Could not build compact data.");
            return;
        }
        
        if ( !m_keepInterResults ){
            rcFreeHeightField(m_solid);
            m_solid = 0;
        }
        
        // Erode the walkable area by agent radius.
        if ( !rcErodeWalkableArea(ctx, m_cfg.walkableRadius, *m_chf) ){
            NSLog(@"buildNavigation: Could not erode.");
            return;
        }
        
        // (Optional) Mark areas.
        const ConvexVolume* vols = geom->getConvexVolumes();
        for (int i  = 0; i < geom->getConvexVolumeCount(); ++i)
            rcMarkConvexPolyArea(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.
            if ( !rcBuildRegionsMonotone(ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea) ){
                NSLog(@"buildNavigation: Could not build regions.");
                return;
            }
        }
        else{
            // Prepare for region partitioning, by calculating distance field along the walkable surface.
            if ( !rcBuildDistanceField(ctx, *m_chf) ){
                NSLog(@"buildNavigation: Could not build distance field.");
                return;
            }
            
            // Partition the walkable surface into simple regions without holes.
            if ( !rcBuildRegions(ctx, *m_chf, m_cfg.borderSize, m_cfg.minRegionArea, m_cfg.mergeRegionArea) ){
                NSLog(@"buildNavigation: Could not build regions.");
                return;
            }
        }
        
        // Create contours.
        rcContourSet *m_cset = rcAllocContourSet();
        if ( !m_cset ){
            NSLog(@"buildNavigation: Out of memory 'cset'.");
            return;
        }
        if ( !rcBuildContours(ctx, *m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, *m_cset) ){
            NSLog(@"buildNavigation: Could not create contours.");
            return;
        }
        
        if ( m_cset->nconts == 0 ){
            NSLog(@"No contours ");
            return;
        }
        
        // Build polygon navmesh from the contours.
        rcPolyMesh *m_pmesh = rcAllocPolyMesh();
        if ( !m_pmesh ){
            NSLog(@"buildNavigation: Out of memory 'pmesh'.");
            return;
        }
        if ( !rcBuildPolyMesh(ctx, *m_cset, m_cfg.maxVertsPerPoly, *m_pmesh) ){
            NSLog(@"buildNavigation: Could not triangulate contours.");
            return;
        }
        
        // Build detail mesh.
        rcPolyMeshDetail *m_dmesh = rcAllocPolyMeshDetail();
        if ( !m_dmesh ){
            NSLog(@"buildNavigation: Out of memory 'dmesh'.");
            return;
        }
        
        if ( !rcBuildPolyMeshDetail(ctx, *m_pmesh, *m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, *m_dmesh) ){
            NSLog(@"buildNavigation: Could build polymesh detail.");
            return;
        }
        
        if ( !m_keepInterResults ){
            rcFreeCompactHeightfield(m_chf);
            m_chf = 0;
            rcFreeContourSet(m_cset);
            m_cset = 0;
        }
        
        unsigned char *navData = NULL;
        int navDataSize;
        
        if ( m_cfg.maxVertsPerPoly <= DT_VERTS_PER_POLYGON ){
            
            if ( m_pmesh->nverts >= 0xffff ){
                // The vertex indices are ushorts, and cannot point to more than 0xffff vertices.
                NSLog(@"Too many vertices per tile %d (max: %d).", m_pmesh->nverts, 0xffff);
                return;
            }
            
            // 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;
                }
            }
            
            dtNavMeshCreateParams params;
            memset(&params, 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 = geom->getOffMeshConnectionVerts();
            params.offMeshConRad = geom->getOffMeshConnectionRads();
            params.offMeshConDir = geom->getOffMeshConnectionDirs();
            params.offMeshConAreas = geom->getOffMeshConnectionAreas();
            params.offMeshConFlags = geom->getOffMeshConnectionFlags();
            params.offMeshConUserID = geom->getOffMeshConnectionId();
            params.offMeshConCount = geom->getOffMeshConnectionCount();
            params.walkableHeight = m_agentHeight;
            params.walkableRadius = m_agentRadius;
            params.walkableClimb = m_agentMaxClimb;
            params.tileX = tx;
            params.tileY = ty;
            params.tileLayer = 0;
            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;
            
            NSLog(@" min: {%0.2f, %0.2f, %0.2f}", m_pmesh->bmin[0], m_pmesh->bmin[1], m_pmesh->bmin[2]);
            NSLog(@" max: {%0.2f, %0.2f, %0.2f}", m_pmesh->bmax[0], m_pmesh->bmax[1], m_pmesh->bmax[2]);
            
            if ( !dtCreateNavMeshData(&params, &navData, &navDataSize) ){
                NSLog(@"Could not build Detour navmesh.");
                return;
            }		
        }
        
        ctx->stopTimer(RC_TIMER_TOTAL);
        
        // save!
        if ( navDataSize > 0 ){
            
            NSString *path = [NSString stringWithFormat:@"%@%d_%d.mesh", directory, tx, ty];
            FILE* fp = fopen([path UTF8String], "wb");
            if (!fp)
                return;
            
            // Store header
            NavMeshSetHeader header;
            header.magic = NAVMESHSET_MAGIC;
            header.version = NAVMESHSET_VERSION;
            header.numTiles = 1;
            fwrite(&header, sizeof(NavMeshSetHeader), 1, fp);
            
            // Store tile
            NavMeshTileHeader tileHeader;
            tileHeader.dataSize = navDataSize;
            fwrite(&tileHeader, sizeof(tileHeader), 1, fp);
            fwrite(navData, navDataSize, 1, fp);
            
            fclose(fp);
        }
        
        NSLog(@"Completed in %0.2f seconds", [start timeIntervalSinceNow] * -1.0f);
        
        if ( geom ){
            delete geom;
        }
    }


    The path I generate is never completed and always returns DT_OUT_OF_NODES and DT_PARTIAL_RESULT

    Thanks again all!
    ~ Tanaris
    Last edited by Tanaris4; 12-12-2011 at 02:18 PM.
    https://tanaris4.com

    Recast + Detour - Connecting tiles
  2. #2
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry to bump - but there have been quite a few views - does anyone have any ideas?

    Thanks in advance!
    ~ Tanaris
    https://tanaris4.com

  3. #3
    hamburger12's Avatar Contributor CoreCoins Purchaser
    Reputation
    87
    Join Date
    Jan 2010
    Posts
    297
    Thanks G/R
    0/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Your tile Location maybe wrong^^ it has something to do with the Orign

  4. #4
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Any suggestion on how I could debug that? And if the tiles don't match up EXACTLY, will it not work? Should there be no overlap?
    https://tanaris4.com

  5. #5
    namreeb's Avatar Legendary

    Reputation
    668
    Join Date
    Sep 2008
    Posts
    1,029
    Thanks G/R
    8/222
    Trade Feedback
    0 (0%)
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    Correct. They must line up exactly. This means that your cell size must exactly divide the tile size. Search this forum for my recast settings. I explained in some detail in that post what variables depend on the others.

  6. #6
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just used your parameters namreeb and I came up with this



    so... close...! The tiles still aren't connected and I'm really not sure why. I took some code from riboncore to get to this point, I believe the offending code is here:

    Code:
    	rcConfig m_cfg;	
    	// Init build configuration from GUI
    	memset(&m_cfg, 0, sizeof(m_cfg));
    	m_cfg.cs = CellSize;
    	m_cfg.ch = CellHeight;
    	m_cfg.walkableSlopeAngle = WalkableSlopeAngle;
    	m_cfg.walkableHeight = (int)ceilf(WorldUnitWalkableHeight / m_cfg.ch);
    	m_cfg.walkableClimb = (int)floorf(WorldUnitWalkableClimb / m_cfg.ch);
    	m_cfg.walkableRadius = (int)ceilf(WorldUnitWalkableRadius / m_cfg.cs);
    	m_cfg.maxEdgeLen = 8;(int)MaxEdgeLen;
    	m_cfg.maxSimplificationError = MaxSimplificationError;
    	m_cfg.minRegionArea = (int)rcSqr(MinRegionSize);		// Note: area = size*size
    	m_cfg.mergeRegionArea = (int)rcSqr(MergeRegionSize);	// Note: area = size*size
    	m_cfg.maxVertsPerPoly = (int)m_vertsPerPoly;
    	m_cfg.tileSize = (int)TileSize;
    	m_cfg.borderSize = m_cfg.walkableRadius + 3; // Reserve enough padding.
    	m_cfg.width = m_cfg.tileSize;// + m_cfg.borderSize*2;
    	m_cfg.height = m_cfg.tileSize;// + m_cfg.borderSize*2;
    	m_cfg.detailSampleDist = DetailSampleDist;
    	m_cfg.detailSampleMaxError = DetailSampleMaxError;
        
        NSLog(@"Cell size: %0.2f", m_cfg.cs);
        NSLog(@"Cell height: %0.2f", m_cfg.ch);
        NSLog(@"Walkable slope angle: %0.2f", m_cfg.walkableSlopeAngle);
        NSLog(@"Walkable height: %d", m_cfg.walkableHeight);
        NSLog(@"Walkable climb: %d", m_cfg.walkableClimb);
        NSLog(@"Walkable radius: %d", m_cfg.walkableRadius);
        NSLog(@"Max edge length: %d", m_cfg.maxEdgeLen);
        NSLog(@"Tile size: %d", m_cfg.tileSize);
        NSLog(@"Border size: %d", m_cfg.borderSize);
        NSLog(@"Height: %d", m_cfg.height);
        NSLog(@"Width: %d", m_cfg.width);
        
        NSLog(@"Max edge length float: %0.2f", (WorldUnitWalkableRadius / CellSize) * 8);
        NSLog(@"%f %f", WorldUnitWalkableRadius, CellSize);
    
        rcVcopy(m_cfg.bmin, bmin);
    	rcVcopy(m_cfg.bmax, bmax);
    
        // pad bounds with a border
    	m_cfg.bmin[0] -= m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmin[2] -= m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmax[0] += m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmax[2] += m_cfg.borderSize*m_cfg.cs;
        
        NSLog(@"Generating mesh (%d, %d) ", tx, ty);
        
        NSLog(@" 3x3 bounds...");
        NSLog(@"  min: {%0.2f, %0.2f, %0.2f}", bmin[0], bmin[1], bmin[2]);
        NSLog(@"  max: {%0.2f, %0.2f, %0.2f}", bmax[0], bmax[1], bmax[2]);
        
        // ** Get our bounds for the tile we care about
        rcMeshLoaderObj *loader2 = CreateMeshLoader(obj);
    	InputGeom *geomTile = new InputGeom();
    	if ( !geomTile->loadMesh(0, loader2) ){
            NSLog(@"Unable to load ObjData2(%d, %d)", tx, ty);
    		return;
    	}
        
        if ( !geomTile || !geomTile->getMesh() || !geomTile->getChunkyMesh() ){
    		NSLog(@"buildNavigation: Input mesh is not specified.2(%d, %d)", tx, ty);
    		return;
    	}
        const float *bminTile = geomTile->getMeshBoundsMin();
    	const float *bmaxTile = geomTile->getMeshBoundsMax();
        
        // save the tile's max/min not the 3x3!
        rcVcopy(m_cfg.bmin, bminTile);
    	rcVcopy(m_cfg.bmax, bmaxTile);
        
        // this sets the dimensions of the heightfield - should maybe happen before border padding
        rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);
        
        NSLog(@"Height: %d", m_cfg.height);
        NSLog(@"Width: %d", m_cfg.width);
        
        // pad bounds with a border
    	m_cfg.bmin[0] -= m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmin[2] -= m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmax[0] += m_cfg.borderSize*m_cfg.cs;
    	m_cfg.bmax[2] += m_cfg.borderSize*m_cfg.cs;
        
        NSLog(@" Tile bounds...");
        NSLog(@"  min: {%0.2f, %0.2f, %0.2f}", m_cfg.bmin[0], m_cfg.bmin[1], m_cfg.bmin[2]);
        NSLog(@"  max: {%0.2f, %0.2f, %0.2f}", m_cfg.bmax[0], m_cfg.bmax[1], m_cfg.bmax[2]);
    Anyone have any ideas? I'm sure it's something so simple I'm missing.

    Thanks!
    ~ Tanaris
    https://tanaris4.com

  7. #7
    namreeb's Avatar Legendary

    Reputation
    668
    Join Date
    Sep 2008
    Posts
    1,029
    Thanks G/R
    8/222
    Trade Feedback
    0 (0%)
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    The cell size does not perfectly divide the tile size. Tile size is 533 + (1/3) so you need to do something like this (which I mentioned in the post you said you read :P):

    Code:
    const float TileSize = 533.0f + (1.0f / 3.0f);
    const int VoxelCount = 1778;
    const float CellSize = TileSize / (float)VoxelCount;
    This ensures that the cell size will always perfectly divide the tile size. To adjust your voxel size, you change only the voxel count variable.

  8. #8
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What do you mean by perfect? b/c the above has a result of 0.29996250468691
    https://tanaris4.com

  9. #9
    namreeb's Avatar Legendary

    Reputation
    668
    Join Date
    Sep 2008
    Posts
    1,029
    Thanks G/R
    8/222
    Trade Feedback
    0 (0%)
    Mentioned
    9 Post(s)
    Tagged
    0 Thread(s)
    Meaning TileSize / CellSize must be an integer.

  10. #10
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I see your point now, but then why does everyone use 533.333333333 as the GRID_SIZE?

    Wouldn't you ideally want your cell size to be the same (I guess or slightly above) WorldUnitWalkableRadius (0.2951389f).

    So if I set my cell size as 0.3, TileSize at 533, and TileVoxelSize as 1778 I should be good to go?

    Sorry I'm asking so many questions about things that should be rather obvious. Just seeking to understand.

    Edit: Am I setting these correctly:
    Code:
    	m_cfg.width = m_cfg.tileSize;// + m_cfg.borderSize*2;
    	m_cfg.height = m_cfg.tileSize;// + m_cfg.borderSize*2;
    Or should it be:

    Code:
    rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, &m_cfg.width, &m_cfg.height);
    Edit 2: Here is the raw parameters printed out:
    Code:
    2011-12-16 17:55:27.089 Pocket-Pather[34121:707] Cell size: 0.30
    2011-12-16 17:55:27.090 Pocket-Pather[34121:707] Cell height: 0.40
    2011-12-16 17:55:27.090 Pocket-Pather[34121:707] Walkable slope angle: 50.00
    2011-12-16 17:55:27.091 Pocket-Pather[34121:707] Walkable height: 5
    2011-12-16 17:55:27.091 Pocket-Pather[34121:707] Walkable climb: 2
    2011-12-16 17:55:27.091 Pocket-Pather[34121:707] Walkable radius: 1
    2011-12-16 17:55:27.092 Pocket-Pather[34121:707] Max edge length: 8
    2011-12-16 17:55:27.092 Pocket-Pather[34121:707] Tile size: 533
    2011-12-16 17:55:27.092 Pocket-Pather[34121:707] Border size: 1
    2011-12-16 17:55:27.093 Pocket-Pather[34121:707] Generating mesh (31, 31) 
    2011-12-16 17:55:27.093 Pocket-Pather[34121:707]  3x3 bounds...
    2011-12-16 17:55:27.093 Pocket-Pather[34121:707]   min: {-1095.64, -132.51, -1104.18}
    2011-12-16 17:55:27.094 Pocket-Pather[34121:707]   max: {-0.00, 221.80, -0.00}
    2011-12-16 17:55:27.239 Pocket-Pather[34121:707]  Tile bounds...
    2011-12-16 17:55:27.240 Pocket-Pather[34121:707]   min: {-533.33, 0.00, -533.33}
    2011-12-16 17:55:27.240 Pocket-Pather[34121:707]   max: {-0.00, 163.87, -0.00}
    2011-12-16 17:55:27.241 Pocket-Pather[34121:707] Height: 1778
    2011-12-16 17:55:27.241 Pocket-Pather[34121:707] Width: 1778
    Last edited by Tanaris4; 12-16-2011 at 05:56 PM.
    https://tanaris4.com

  11. #11
    guizmows's Avatar Banned
    Reputation
    57
    Join Date
    Feb 2008
    Posts
    414
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    check my pm Tanaris4

  12. #12
    Bananenbrot's Avatar Contributor
    Reputation
    153
    Join Date
    Nov 2009
    Posts
    384
    Thanks G/R
    1/3
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    it's 533.33333333333 (or 1600/3) because one mcnk is 33.3333 (100/3 == (1600 / 3) / 16).
    So, if you calculate based on a 533 tile size there will be a rounding error that would reflect itself in one or the other way into your output mesh.
    I chose mcnk boundaries as tile size and even that caused overflow errors in triangle indices iirc...

  13. #13
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So I think I finally got it! But i'm running into a very strange issue. I'm just trying to gen a path from one point in AB to another, but if I literally increase the end point by like 20 yards it fails, which is strange, b/c it's in the same tile. Any ideas? I know RecastDemo is limited to 256 polys (max length), but i definitely haven't hit that, it's just going across about 3 tiles:

    Edit: I've uploaded a video, watch the LAST click I make: http://www.youtube.com/watch?v=uupM_h_m2f8

    Works:


    Fails:


    Edit 2: When I try to build the path using findPath, I'm getting back DT_PARTIAL_RESULT and DT_OUT_OF_NODES, which is horribly confusing me

    Edit 3: GOT IT! dtStatus status = m_navQuery->init(_navMesh, 65536);
    Last edited by Tanaris4; 12-21-2011 at 04:54 PM.
    https://tanaris4.com

Similar Threads

  1. Path Generator – Recast/Detour and WowMapper – Step
    By RivaLfr in forum WoW Memory Editing
    Replies: 32
    Last Post: 05-13-2022, 05:38 AM
  2. Recast/Detour - 16 tiles per ADT - Proper method to save/load?
    By Tanaris4 in forum WoW Memory Editing
    Replies: 5
    Last Post: 12-29-2011, 12:48 PM
  3. Pathing w/Recast + Detour - Potential issue - thoughts?
    By Tanaris4 in forum WoW Memory Editing
    Replies: 0
    Last Post: 12-12-2011, 10:41 AM
  4. Replies: 1
    Last Post: 12-12-2011, 02:31 AM
  5. [Link] C++ Recast/Detour Wrapper
    By Millow in forum WoW Memory Editing
    Replies: 11
    Last Post: 08-02-2011, 04:26 AM
All times are GMT -5. The time now is 10:51 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search