Пример #1
0
        public void ClearComputedData()
        {
            m_ctx = new Recast.BuildContext();

            m_triareas = null;
            m_solid    = null;
            m_chf      = null;
            m_cset     = null;
            m_pmesh    = null;
            m_cfg      = null;
            m_dmesh    = null;

            m_navMesh  = null;
            m_navQuery = null;

            m_bmin = new float[3];
            m_bmax = new float[3];
        }
Пример #2
0
    public static void ShowRecastNavmesh(DbgRenderMesh renderMesh, Recast.rcPolyMesh pmesh, Recast.rcConfig config)
    {
        renderMesh.Clear();

        UnityEngine.Random.seed = c_RandomSeed;

        int npolys = pmesh.npolys;
        int nvp    = pmesh.nvp;

        int[]     tri   = new int[3];
        Vector3[] verts = new Vector3[3];
        for (int i = 0; i < npolys; ++i)
        {
            int   pIndex = i * nvp * 2;
            Color col    = Color.blue;         //new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
            for (int j = 2; j < nvp; ++j)
            {
                if (pmesh.polys[pIndex + j] == Recast.RC_MESH_NULL_IDX)
                {
                    break;
                }
                tri[0] = pmesh.polys[pIndex];
                tri[1] = pmesh.polys[pIndex + j - 1];
                tri[2] = pmesh.polys[pIndex + j];

                for (int k = 0; k < 3; ++k)
                {
                    int vIndex = tri[k] * 3;
                    verts[k].x = config.bmin[0] + pmesh.verts[vIndex + 0] * pmesh.cs;
                    verts[k].y = config.bmin[1] + (pmesh.verts[vIndex + 1] + 1) * pmesh.ch + 0.1f;
                    verts[k].z = config.bmin[2] + pmesh.verts[vIndex + 2] * pmesh.cs;
                }
                col = VaryColor(col);
                renderMesh.AddTriangle(new DbgRenderTriangle(verts[0], verts[1], verts[2], col));
            }
        }
        renderMesh.Rebuild();
    }
Пример #3
0
        //Compute Recast and Detour navmesh
        public bool ComputeSystem()
        {
            ClearComputedData();

            Recast.rcCalcBounds(m_verts, m_vertCount, m_bmin, m_bmax);

            //
            // Step 1. Initialize build config.
            //

            // Init build configuration from GUI
            m_cfg = new Recast.rcConfig();

            m_cfg.cs = m_RecastMeshParams.m_cellSize;
            m_cfg.ch = m_RecastMeshParams.m_cellHeight;
            m_cfg.walkableSlopeAngle     = m_RecastMeshParams.m_agentMaxSlope;
            m_cfg.walkableHeight         = (int)Math.Ceiling(m_RecastMeshParams.m_agentHeight / m_cfg.ch);
            m_cfg.walkableClimb          = (int)Math.Floor(m_RecastMeshParams.m_agentMaxClimb / m_cfg.ch);
            m_cfg.walkableRadius         = (int)Math.Ceiling(m_RecastMeshParams.m_agentRadius / m_cfg.cs);
            m_cfg.maxEdgeLen             = (int)(m_RecastMeshParams.m_edgeMaxLen / m_RecastMeshParams.m_cellSize);
            m_cfg.maxSimplificationError = m_RecastMeshParams.m_edgeMaxError;
            m_cfg.minRegionArea          = (int)(m_RecastMeshParams.m_regionMinSize * m_RecastMeshParams.m_regionMinSize);              // Note: area = size*size
            m_cfg.mergeRegionArea        = (int)(m_RecastMeshParams.m_regionMergeSize * m_RecastMeshParams.m_regionMergeSize);          // Note: area = size*size
            m_cfg.maxVertsPerPoly        = (int)m_RecastMeshParams.m_vertsPerPoly;
            m_cfg.detailSampleDist       = m_RecastMeshParams.m_detailSampleDist < 0.9f ? 0 : m_RecastMeshParams.m_cellSize * m_RecastMeshParams.m_detailSampleDist;
            m_cfg.detailSampleMaxError   = m_RecastMeshParams.m_cellHeight * m_RecastMeshParams.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.
            Recast.rcVcopy(m_cfg.bmin, m_bmin);
            Recast.rcVcopy(m_cfg.bmax, m_bmax);
            Recast.rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, out m_cfg.width, out m_cfg.height);

            // Reset build times gathering.
            m_ctx.resetTimers();

            // Start the build process.
            m_ctx.startTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, "Building navigation:");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_cfg.width + " x " + m_cfg.height + " cells");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_vertCount / 1000.0f + "K verts, " + m_triCount / 1000.0f + "K tris");

            //
            // Step 2. Rasterize input polygon soup.
            //

            // Allocate voxel heightfield where we rasterize our input data to.
            m_solid = new Recast.rcHeightfield();
            if (m_solid == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
                return(false);
            }
            if (!Recast.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(Recast.rcLogCategory.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 byte[m_triCount];
            if (m_triareas == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (" + m_triCount + ").");
                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(byte));

            Recast.rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, m_verts, m_vertCount, m_tris, m_triCount, m_triareas);
            Recast.rcRasterizeTriangles(m_ctx, m_verts, m_vertCount, m_tris, m_triareas, m_triCount, m_solid, m_cfg.walkableClimb);

            if (!m_keepInterResults)
            {
                m_triareas = null;
            }

            //
            // 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.
            Recast.rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, m_solid);
            Recast.rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid);
            Recast.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 = new Recast.rcCompactHeightfield();
            if (m_chf == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
                return(false);
            }
            if (!Recast.rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid, m_chf))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
                return(false);
            }

            if (!m_keepInterResults)
            {
                m_solid = null;
            }

            // Erode the walkable area by agent radius.
            if (!Recast.rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, m_chf))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not erode.");
                return(false);
            }

            /*
             * // (Optional) Mark areas.
             * 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, (byte)vols[i].area, *m_chf);
             */

            if (m_RecastMeshParams.m_monotonePartitioning)
            {
                // Partition the walkable surface into simple regions without holes.
                // Monotone partitioning does not need distancefield.
                if (!Recast.rcBuildRegionsMonotone(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return(false);
                }
            }
            else
            {
                // Prepare for region partitioning, by calculating distance field along the walkable surface.
                if (!Recast.rcBuildDistanceField(m_ctx, m_chf))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
                    return(false);
                }

                // Partition the walkable surface into simple regions without holes.
                if (!Recast.rcBuildRegions(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return(false);
                }
            }

            //
            // Step 5. Trace and simplify region contours.
            //

            // Create contours.
            m_cset = new Recast.rcContourSet();
            if (m_cset == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
                return(false);
            }
            if (!Recast.rcBuildContours(m_ctx, m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, m_cset, -1))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not create contours.");
                return(false);
            }

            //m_cset.dumpToTxt("Data/CSET_dump.txt");

            //
            // Step 6. Build polygons mesh from contours.
            //

            // Build polygon navmesh from the contours.
            m_pmesh = new Recast.rcPolyMesh();
            if (m_pmesh == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
                return(false);
            }
            if (!Recast.rcBuildPolyMesh(m_ctx, m_cset, m_cfg.maxVertsPerPoly, m_pmesh))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
                return(false);
            }

            //m_pmesh.dumpToObj("Data/navmesh.obj");
            //m_pmesh.dumpToText("Data/navmesh.txt");

            //
            // Step 7. Create detail mesh which allows to access approximate height on each polygon.
            //

            m_dmesh = new Recast.rcPolyMeshDetail();            //rcAllocPolyMeshDetail();
            if (m_dmesh == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
                return(false);
            }

            if (!Recast.rcBuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, m_dmesh))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
                return(false);
            }

            //m_dmesh.dumpToText("Data/polymeshdetail_cs.txt");
            //m_dmesh.dumpToObj("Data/polymeshdetail_cs.obj");

            if (!m_keepInterResults)
            {
                m_chf  = null;
                m_cset = null;
            }

            // 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.
            //

            // 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 <= Detour.DT_VERTS_PER_POLYGON)
            {
                //unsigned char* navData = 0;
                Detour.dtRawTileData navData = null;
                //int navDataSize = 0;

                // Update poly flags from areas.
                for (int i = 0; i < m_pmesh.npolys; ++i)
                {
                    if (m_pmesh.areas[i] == Recast.RC_WALKABLE_AREA)
                    {
                        m_pmesh.areas[i] = (byte)SamplePolyAreas.GROUND;
                    }

                    if (m_pmesh.areas[i] == (byte)SamplePolyAreas.GROUND)
                    {
                        m_pmesh.flags[i] = (ushort)SamplePolyFlags.WALK;
                    }

                    /*
                     * if (m_pmesh.areas[i] == Recast.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;
                     * }*/
                }

                Detour.dtNavMeshCreateParams navMeshCreateParams = new Detour.dtNavMeshCreateParams();
                navMeshCreateParams.verts            = m_pmesh.verts;
                navMeshCreateParams.vertCount        = m_pmesh.nverts;
                navMeshCreateParams.polys            = m_pmesh.polys;
                navMeshCreateParams.polyAreas        = m_pmesh.areas;
                navMeshCreateParams.polyFlags        = m_pmesh.flags;
                navMeshCreateParams.polyCount        = m_pmesh.npolys;
                navMeshCreateParams.nvp              = m_pmesh.nvp;
                navMeshCreateParams.detailMeshes     = m_dmesh.meshes;
                navMeshCreateParams.detailVerts      = m_dmesh.verts;
                navMeshCreateParams.detailVertsCount = m_dmesh.nverts;
                navMeshCreateParams.detailTris       = m_dmesh.tris;
                navMeshCreateParams.detailTriCount   = m_dmesh.ntris;
                navMeshCreateParams.offMeshConVerts  = null;            //m_geom.getOffMeshConnectionVerts();
                navMeshCreateParams.offMeshConRad    = null;            //m_geom.getOffMeshConnectionRads();
                navMeshCreateParams.offMeshConDir    = null;            //m_geom.getOffMeshConnectionDirs();
                navMeshCreateParams.offMeshConAreas  = null;            //m_geom.getOffMeshConnectionAreas();
                navMeshCreateParams.offMeshConFlags  = null;            //m_geom.getOffMeshConnectionFlags();
                navMeshCreateParams.offMeshConUserID = null;            //m_geom.getOffMeshConnectionId();
                navMeshCreateParams.offMeshConCount  = 0;               //m_geom.getOffMeshConnectionCount();
                navMeshCreateParams.walkableHeight   = m_RecastMeshParams.m_agentHeight;
                navMeshCreateParams.walkableRadius   = m_RecastMeshParams.m_agentRadius;
                navMeshCreateParams.walkableClimb    = m_RecastMeshParams.m_agentMaxClimb;
                Recast.rcVcopy(navMeshCreateParams.bmin, m_pmesh.bmin);
                Recast.rcVcopy(navMeshCreateParams.bmax, m_pmesh.bmax);
                navMeshCreateParams.cs          = m_cfg.cs;
                navMeshCreateParams.ch          = m_cfg.ch;
                navMeshCreateParams.buildBvTree = true;

                if (!Detour.dtCreateNavMeshData(navMeshCreateParams, out navData))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not build Detour navmesh.");
                    return(false);
                }

                m_navMesh = new Detour.dtNavMesh();
                if (m_navMesh == null)
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not create Detour navmesh");
                    return(false);
                }

                dtStatus status;

                status = m_navMesh.init(navData, (int)Detour.dtTileFlags.DT_TILE_FREE_DATA);
                if (Detour.dtStatusFailed(status))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh");
                    return(false);
                }

                m_navQuery = new Detour.dtNavMeshQuery();
                status     = m_navQuery.init(m_navMesh, 2048);
                if (Detour.dtStatusFailed(status))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh query");
                    return(false);
                }

                m_rawTileData = navData;
            }
            else
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_WARNING, "Detour does not support more than " + Detour.DT_VERTS_PER_POLYGON + " verts per polygon. A navmesh has not been generated.");
            }

            m_ctx.stopTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            // Show performance stats.
            m_ctx.logBuildTimes();
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, ">> Polymesh: " + m_pmesh.nverts + " vertices  " + m_pmesh.npolys + " polygons");

            m_totalBuildTimeMs = (float)m_ctx.getAccumulatedTime(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            return(true);
        }
Пример #4
0
        //Compute Recast and Detour navmesh
        public bool ComputeSystem()
        {
            ClearComputedData();

            Recast.rcCalcBounds(m_verts, m_vertCount, m_bmin, m_bmax);

            //
            // Step 1. Initialize build config.
            //

            // Init build configuration from GUI
            m_cfg = new Recast.rcConfig();

            m_cfg.cs = m_RecastMeshParams.m_cellSize;
            m_cfg.ch = m_RecastMeshParams.m_cellHeight;
            m_cfg.walkableSlopeAngle = m_RecastMeshParams.m_agentMaxSlope;
            m_cfg.walkableHeight = (int)Math.Ceiling(m_RecastMeshParams.m_agentHeight / m_cfg.ch);
            m_cfg.walkableClimb = (int)Math.Floor(m_RecastMeshParams.m_agentMaxClimb / m_cfg.ch);
            m_cfg.walkableRadius = (int)Math.Ceiling(m_RecastMeshParams.m_agentRadius / m_cfg.cs);
            m_cfg.maxEdgeLen = (int)(m_RecastMeshParams.m_edgeMaxLen / m_RecastMeshParams.m_cellSize);
            m_cfg.maxSimplificationError = m_RecastMeshParams.m_edgeMaxError;
            m_cfg.minRegionArea = (int)(m_RecastMeshParams.m_regionMinSize * m_RecastMeshParams.m_regionMinSize);		// Note: area = size*size
            m_cfg.mergeRegionArea = (int)(m_RecastMeshParams.m_regionMergeSize * m_RecastMeshParams.m_regionMergeSize);	// Note: area = size*size
            m_cfg.maxVertsPerPoly = (int)m_RecastMeshParams.m_vertsPerPoly;
            m_cfg.detailSampleDist = m_RecastMeshParams.m_detailSampleDist < 0.9f ? 0 : m_RecastMeshParams.m_cellSize * m_RecastMeshParams.m_detailSampleDist;
            m_cfg.detailSampleMaxError = m_RecastMeshParams.m_cellHeight * m_RecastMeshParams.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.
            Recast.rcVcopy(m_cfg.bmin, m_bmin);
            Recast.rcVcopy(m_cfg.bmax, m_bmax);
            Recast.rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, out m_cfg.width, out m_cfg.height);

            // Reset build times gathering.
            m_ctx.resetTimers();

            // Start the build process.
            m_ctx.startTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, "Building navigation:");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_cfg.width + " x " + m_cfg.height + " cells");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_vertCount / 1000.0f + "K verts, " + m_triCount / 1000.0f + "K tris");

            //
            // Step 2. Rasterize input polygon soup.
            //

            // Allocate voxel heightfield where we rasterize our input data to.
            m_solid = new Recast.rcHeightfield();
            if (m_solid == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
                return false;
            }
            if (!Recast.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(Recast.rcLogCategory.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 byte[m_triCount];
            if (m_triareas == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (" + m_triCount + ").");
                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(byte));

            Recast.rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, m_verts, m_vertCount, m_tris, m_triCount, m_triareas);
            Recast.rcRasterizeTriangles(m_ctx, m_verts, m_vertCount, m_tris, m_triareas, m_triCount, m_solid, m_cfg.walkableClimb);

            if (!m_keepInterResults) {
                m_triareas = null;
            }

            //
            // 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.
            Recast.rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, m_solid);
            Recast.rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid);
            Recast.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 = new Recast.rcCompactHeightfield();
            if (m_chf == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
                return false;
            }
            if (!Recast.rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid, m_chf)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
                return false;
            }

            if (!m_keepInterResults) {
                m_solid = null;
            }

            // Erode the walkable area by agent radius.
            if (!Recast.rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, m_chf)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not erode.");
                return false;
            }

            /*
                // (Optional) Mark areas.
                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, (byte)vols[i].area, *m_chf);
                */

            if (m_RecastMeshParams.m_monotonePartitioning) {
                // Partition the walkable surface into simple regions without holes.
                // Monotone partitioning does not need distancefield.
                if (!Recast.rcBuildRegionsMonotone(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return false;
                }
            } else {
                // Prepare for region partitioning, by calculating distance field along the walkable surface.
                if (!Recast.rcBuildDistanceField(m_ctx, m_chf)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
                    return false;
                }

                // Partition the walkable surface into simple regions without holes.
                if (!Recast.rcBuildRegions(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return false;
                }
            }

            //
            // Step 5. Trace and simplify region contours.
            //

            // Create contours.
            m_cset = new Recast.rcContourSet();
            if (m_cset == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
                return false;
            }
            if (!Recast.rcBuildContours(m_ctx, m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, m_cset, -1)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not create contours.");
                return false;
            }

            //m_cset.dumpToTxt("Data/CSET_dump.txt");

            //
            // Step 6. Build polygons mesh from contours.
            //

            // Build polygon navmesh from the contours.
            m_pmesh = new Recast.rcPolyMesh();
            if (m_pmesh == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
                return false;
            }
            if (!Recast.rcBuildPolyMesh(m_ctx, m_cset, m_cfg.maxVertsPerPoly, m_pmesh)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
                return false;
            }

            //m_pmesh.dumpToObj("Data/navmesh.obj");
            //m_pmesh.dumpToText("Data/navmesh.txt");

            //
            // Step 7. Create detail mesh which allows to access approximate height on each polygon.
            //

            m_dmesh = new Recast.rcPolyMeshDetail();//rcAllocPolyMeshDetail();
            if (m_dmesh == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
                return false;
            }

            if (!Recast.rcBuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, m_dmesh)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
                return false;
            }

            //m_dmesh.dumpToText("Data/polymeshdetail_cs.txt");
            //m_dmesh.dumpToObj("Data/polymeshdetail_cs.obj");

            if (!m_keepInterResults) {

                m_chf = null;
                m_cset = null;
            }

            // 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.
            //

            // 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 <= Detour.DT_VERTS_PER_POLYGON) {
                //unsigned char* navData = 0;
                Detour.dtRawTileData navData = null;
                //int navDataSize = 0;

                // Update poly flags from areas.
                for (int i = 0; i < m_pmesh.npolys; ++i) {
                    if (m_pmesh.areas[i] == Recast.RC_WALKABLE_AREA)
                        m_pmesh.areas[i] = (byte)SamplePolyAreas.GROUND;

                    if (m_pmesh.areas[i] == (byte)SamplePolyAreas.GROUND) {
                        m_pmesh.flags[i] = (ushort)SamplePolyFlags.WALK;
                    }

                    /*
                        if (m_pmesh.areas[i] == Recast.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;
                        }*/
                }

                Detour.dtNavMeshCreateParams navMeshCreateParams = new Detour.dtNavMeshCreateParams();
                navMeshCreateParams.verts = m_pmesh.verts;
                navMeshCreateParams.vertCount = m_pmesh.nverts;
                navMeshCreateParams.polys = m_pmesh.polys;
                navMeshCreateParams.polyAreas = m_pmesh.areas;
                navMeshCreateParams.polyFlags = m_pmesh.flags;
                navMeshCreateParams.polyCount = m_pmesh.npolys;
                navMeshCreateParams.nvp = m_pmesh.nvp;
                navMeshCreateParams.detailMeshes = m_dmesh.meshes;
                navMeshCreateParams.detailVerts = m_dmesh.verts;
                navMeshCreateParams.detailVertsCount = m_dmesh.nverts;
                navMeshCreateParams.detailTris = m_dmesh.tris;
                navMeshCreateParams.detailTriCount = m_dmesh.ntris;
                navMeshCreateParams.offMeshConVerts = null;//m_geom.getOffMeshConnectionVerts();
                navMeshCreateParams.offMeshConRad = null;//m_geom.getOffMeshConnectionRads();
                navMeshCreateParams.offMeshConDir = null;//m_geom.getOffMeshConnectionDirs();
                navMeshCreateParams.offMeshConAreas = null;//m_geom.getOffMeshConnectionAreas();
                navMeshCreateParams.offMeshConFlags = null;//m_geom.getOffMeshConnectionFlags();
                navMeshCreateParams.offMeshConUserID = null;//m_geom.getOffMeshConnectionId();
                navMeshCreateParams.offMeshConCount = 0;//m_geom.getOffMeshConnectionCount();
                navMeshCreateParams.walkableHeight = m_RecastMeshParams.m_agentHeight;
                navMeshCreateParams.walkableRadius = m_RecastMeshParams.m_agentRadius;
                navMeshCreateParams.walkableClimb = m_RecastMeshParams.m_agentMaxClimb;
                Recast.rcVcopy(navMeshCreateParams.bmin, m_pmesh.bmin);
                Recast.rcVcopy(navMeshCreateParams.bmax, m_pmesh.bmax);
                navMeshCreateParams.cs = m_cfg.cs;
                navMeshCreateParams.ch = m_cfg.ch;
                navMeshCreateParams.buildBvTree = true;

                if (!Detour.dtCreateNavMeshData(navMeshCreateParams, out navData)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not build Detour navmesh.");
                    return false;
                }

                m_navMesh = new Detour.dtNavMesh();
                if (m_navMesh == null) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not create Detour navmesh");
                    return false;
                }

                dtStatus status;

                status = m_navMesh.init(navData, (int)Detour.dtTileFlags.DT_TILE_FREE_DATA);
                if (Detour.dtStatusFailed(status)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh");
                    return false;
                }

                m_navQuery = new Detour.dtNavMeshQuery();
                status = m_navQuery.init(m_navMesh, 2048);
                if (Detour.dtStatusFailed(status)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh query");
                    return false;
                }

                m_rawTileData = navData;
            } else {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_WARNING, "Detour does not support more than " + Detour.DT_VERTS_PER_POLYGON + " verts per polygon. A navmesh has not been generated.");
            }

            m_ctx.stopTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            // Show performance stats.
            m_ctx.logBuildTimes();
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, ">> Polymesh: " + m_pmesh.nverts + " vertices  " + m_pmesh.npolys + " polygons");

            m_totalBuildTimeMs = (float) m_ctx.getAccumulatedTime(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            return true;
        }
Пример #5
0
        public void ClearComputedData()
        {
            m_ctx = new Recast.BuildContext();

            m_triareas = null;
            m_solid = null;
            m_chf = null;
            m_cset = null;
            m_pmesh = null;
            m_cfg = null;
            m_dmesh = null;

            m_navMesh = null;
            m_navQuery = null;

            m_bmin = new float[3];
            m_bmax = new float[3];
        }