예제 #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 ShowContours(DbgRenderMesh renderMesh, Recast.rcContourSet cset)
    {
        renderMesh.Clear();

        UnityEngine.Random.seed = c_RandomSeed;

        float[] orig = cset.bmin;
        float   cs   = cset.cs;
        float   ch   = cset.ch;

        for (int i = 0; i < cset.nconts; ++i)
        {
            Recast.rcContour c = cset.conts[i];
            if (c.nverts == 0)
            {
                continue;
            }

            Color col  = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);
            Color bcol = VaryColor(col);

            for (int j = 0, k = c.nverts - 1; j < c.nverts; k = j++)
            {
                int   vaStart = k * 4;
                int   vbStart = j * 4;
                Color segCol  = ((c.verts[vaStart + 3] & Recast.RC_AREA_BORDER) != 0) ? bcol : col;

                Vector3 start = new Vector3(orig[0] + c.verts[vaStart + 0] * cs,
                                            orig[1] + (c.verts[vaStart + 1] + 1 + (i & 1)) * ch,
                                            orig[2] + c.verts[vaStart + 2] * cs);
                Vector3 end = new Vector3(orig[0] + c.verts[vbStart + 0] * cs,
                                          orig[1] + (c.verts[vbStart + 1] + 1 + (i & 1)) * ch,
                                          orig[2] + c.verts[vbStart + 2] * cs);

                renderMesh.AddVerticalQuad(start, end, 0.5f, segCol);
            }
        }

        /*
         *              dd->begin(DU_DRAW_POINTS, 3.0f);
         *
         *              for (int i = 0; i < cset.nconts; ++i)
         *              {
         *                      const rcContour& c = cset.conts[i];
         *                      unsigned int color = duDarkenCol(duIntToCol(c.reg, a));
         *                      for (int j = 0; j < c.nverts; ++j)
         *                      {
         *                              const int* v = &c.verts[j*4];
         *                              float off = 0;
         *                              unsigned int colv = color;
         *                              if (v[3] & RC_BORDER_VERTEX)
         *                              {
         *                                      colv = duRGBA(255,255,255,a);
         *                                      off = ch*2;
         *                              }
         *
         *                              float fx = orig[0] + v[0]*cs;
         *                              float fy = orig[1] + (v[1]+1+(i&1))*ch + off;
         *                              float fz = orig[2] + v[2]*cs;
         *                                  fx,fy,fz, colv);
         *                      }
         *              }
         */
        renderMesh.Rebuild();
    }
예제 #3
0
    public static void ShowRawContours(DbgRenderMesh renderMesh, Recast.rcContourSet cset)
    {
        renderMesh.Clear();

        UnityEngine.Random.seed = c_RandomSeed;

        float[] orig = cset.bmin;
        float   cs   = cset.cs;
        float   ch   = cset.ch;

        for (int i = 0; i < cset.nconts; ++i)
        {
            Recast.rcContour c = cset.conts[i];

            if (c.nrverts == 0)
            {
                continue;
            }

            Color col = new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value);

            int triStartIndex = renderMesh.GetTriangleCount();

            Vector3 start = new Vector3(orig[0] + c.rverts[0] * cs,
                                        orig[1] + (c.rverts[1] + 1 + (i & 1)) * ch,
                                        orig[2] + c.rverts[2] * cs);
            Vector3 a = Vector3.zero;
            Vector3 b = start;
            for (int j = 1; j < c.nrverts; ++j)
            {
                a = b;
                int vStart = j * 4;
                b = new Vector3(orig[0] + c.rverts[vStart + 0] * cs,
                                orig[1] + (c.rverts[vStart + 1] + 1 + (i & 1)) * ch,
                                orig[2] + c.rverts[vStart + 2] * cs);
                if (j > 0)
                {
                    renderMesh.AddVerticalQuad(a, b, 0.5f, col);
                }
            }
            // Loop last segment.
            renderMesh.AddVerticalQuad(b, start, 0.5f, col);

            int triEndIndex = renderMesh.GetTriangleCount();

            Vector3 labelPos = renderMesh.GetBoundingBoxTop(triStartIndex, triEndIndex);

            renderMesh.AddLabel(labelPos, "contour " + i + "\nReg: " + c.reg + "\nnrverts:" + c.nrverts + "\nnverts:" + c.nverts);
        }

        /*
         *              dd->end();
         *
         *              dd->begin(DU_DRAW_POINTS, 2.0f);
         *
         *              for (int i = 0; i < cset.nconts; ++i)
         *              {
         *                      const rcContour& c = cset.conts[i];
         *                      unsigned int color = duDarkenCol(duIntToCol(c.reg, a));
         *
         *                      for (int j = 0; j < c.nrverts; ++j)
         *                      {
         *                              const int* v = &c.rverts[j*4];
         *                              float off = 0;
         *                              unsigned int colv = color;
         *                              if (v[3] & RC_BORDER_VERTEX)
         *                              {
         *                                      colv = duRGBA(255,255,255,a);
         *                                      off = ch*2;
         *                              }
         *
         *                              float fx = orig[0] + v[0]*cs;
         *                              float fy = orig[1] + (v[1]+1+(i&1))*ch + off;
         *                              float fz = orig[2] + v[2]*cs;
         *                                  fx,fy,fz, colv);
         *                      }
         *              }
         *              dd->end();
         */
        renderMesh.Rebuild();
    }
예제 #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
        //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;
        }
예제 #6
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];
        }