Beispiel #1
0
        private static bool inCone(int i, int n, int[] verts, int pj, int[] vertpj)
        {
            int pi   = i * 4;
            int pi1  = RecastMesh.next(i, n) * 4;
            int pin1 = RecastMesh.prev(i, n) * 4;

            int[] pverts = new int[4 * 4];
            for (int g = 0; g < 4; g++)
            {
                pverts[g]      = verts[pi + g];
                pverts[4 + g]  = verts[pi1 + g];
                pverts[8 + g]  = verts[pin1 + g];
                pverts[12 + g] = vertpj[pj + g];
            }
            pi   = 0;
            pi1  = 4;
            pin1 = 8;
            pj   = 12;
            // If P[i] is a convex vertex [ i+1 left or on (i-1,i) ].
            if (RecastMesh.leftOn(pverts, pin1, pi, pi1))
            {
                return(RecastMesh.left(pverts, pi, pj, pin1) && RecastMesh.left(pverts, pj, pi, pi1));
            }
            // Assume (i-1,i,i+1) not collinear.
            // else P[i] is reflex.
            return(!(RecastMesh.leftOn(pverts, pi, pj, pi1) && RecastMesh.leftOn(pverts, pj, pi, pin1)));
        }
Beispiel #2
0
 /// <summary>
 /// Unloads a zone
 /// </summary>
 /// <param name="z"></param>
 public static void Unload(Zone2 z)
 {
     lock (_loadedZones)
     {
         if (_loadedZones.ContainsKey(z.ID))
         {
             RecastMesh m = _loadedZones[z.ID];
             if (m != null)
             {
                 FreeNavMesh(m.meshPtr, m.queryPtr);
             }
             _loadedZones.Remove(z.ID);
         }
     }
 }
Beispiel #3
0
        private static bool intersectSegCountour(int d0, int d1, int i, int n, int[] verts, int[] d0verts, int[] d1verts)
        {
            // For each edge (k,k+1) of P
            int[] pverts = new int[4 * 4];
            for (int g = 0; g < 4; g++)
            {
                pverts[g]     = d0verts[d0 + g];
                pverts[4 + g] = d1verts[d1 + g];
            }
            d0 = 0;
            d1 = 4;
            for (int k = 0; k < n; k++)
            {
                int k1 = RecastMesh.next(k, n);
                // Skip edges incident to i.
                if (i == k || i == k1)
                {
                    continue;
                }
                int p0 = k * 4;
                int p1 = k1 * 4;
                for (int g = 0; g < 4; g++)
                {
                    pverts[8 + g]  = verts[p0 + g];
                    pverts[12 + g] = verts[p1 + g];
                }
                p0 = 8;
                p1 = 12;
                if (RecastMesh.vequal(pverts, d0, p0) || RecastMesh.vequal(pverts, d1, p0) || RecastMesh.vequal(pverts, d0, p1) || RecastMesh.vequal(pverts, d1, p1))
                {
                    continue;
                }

                if (RecastMesh.intersect(pverts, d0, d1, p0, p1))
                {
                    return(true);
                }
            }
            return(false);
        }
Beispiel #4
0
        private static void removeDegenerateSegments(List <int> simplified)
        {
            // Remove adjacent vertices which are equal on xz-plane,
            // or else the triangulator will get confused.
            int npts = simplified.Count / 4;

            for (int i = 0; i < npts; ++i)
            {
                int ni = RecastMesh.next(i, npts);

                //			if (vequal(&simplified[i*4], &simplified[ni*4]))
                if (simplified[i * 4] == simplified[ni * 4] && simplified[i * 4 + 2] == simplified[ni * 4 + 2])
                {
                    // Degenerate segment, remove.
                    simplified.RemoveAt(i * 4);
                    simplified.RemoveAt(i * 4);
                    simplified.RemoveAt(i * 4);
                    simplified.RemoveAt(i * 4);
                    npts--;
                }
            }
        }
Beispiel #5
0
        /// <summary>
        /// Gets or loads a recast mesh
        /// </summary>
        private static RecastMesh LoadZoneMesh(Zone2 zone)
        {
            lock (_loadedZones) {
                if (_loadedZones.ContainsKey(zone.ID))
                {
                    return(_loadedZones[zone.ID]);
                }

                RecastMesh mesh = null;
                try {
                    string file = zone.NavFile;
                    if (!File.Exists(file))
                    {
                        return(null);              // no navmesh available
                    }
                    file = Path.GetFullPath(file); // not sure if c dll can load relative stuff
                    IntPtr meshPtr  = IntPtr.Zero;
                    IntPtr queryPtr = IntPtr.Zero;

                    if (!LoadNavMesh(file, ref meshPtr, ref queryPtr))
                    {
                        Log.Error("Loading NavMesh failed for {0}!", zone);
                        return(null);
                    }

                    if (meshPtr == IntPtr.Zero || queryPtr == IntPtr.Zero)
                    {
                        Log.Error("Loading NavMesh failed for {0}! (Pointer was zero!)", zone);
                        return(null);
                    }
                    Log.Normal("Loading NavMesh sucessful for region {0}", zone);
                    return(mesh = new RecastMesh(meshPtr, queryPtr));
                }
                finally {
                    _loadedZones.Add(zone.ID, mesh);
                }
            }
        }
Beispiel #6
0
        public virtual RecastBuilderResult build(InputGeom geom, RecastBuilderConfig bcfg)
        {
            RecastConfig       cfg = bcfg.cfg;
            Context            ctx = new Context();
            CompactHeightfield chf = buildCompactHeightfield(geom, bcfg, ctx);

            // Partition the heightfield so that we can use simple algorithm later
            // to triangulate the walkable areas.
            // There are 3 martitioning methods, each with some pros and cons:
            // 1) Watershed partitioning
            // - the classic Recast partitioning
            // - creates the nicest tessellation
            // - usually slowest
            // - partitions the heightfield into nice regions without holes or
            // overlaps
            // - the are some corner cases where this method creates produces holes
            // and overlaps
            // - holes may appear when a small obstacles is close to large open area
            // (triangulation can handle this)
            // - overlaps may occur if you have narrow spiral corridors (i.e
            // stairs), this make triangulation to fail
            // * generally the best choice if you precompute the nacmesh, use this
            // if you have large open areas
            // 2) Monotone partioning
            // - fastest
            // - partitions the heightfield into regions without holes and overlaps
            // (guaranteed)
            // - creates long thin polygons, which sometimes causes paths with
            // detours
            // * use this if you want fast navmesh generation
            // 3) Layer partitoining
            // - quite fast
            // - partitions the heighfield into non-overlapping regions
            // - relies on the triangulation code to cope with holes (thus slower
            // than monotone partitioning)
            // - produces better triangles than monotone partitioning
            // - does not have the corner cases of watershed partitioning
            // - can be slow and create a bit ugly tessellation (still better than
            // monotone)
            // if you have large open areas with small obstacles (not a problem if
            // you use tiles)
            // * good choice to use for tiled navmesh with medium and small sized
            // tiles

            if (cfg.partitionType == PartitionType.WATERSHED)
            {
                // Prepare for region partitioning, by calculating distance field
                // along the walkable surface.
                RecastRegion.buildDistanceField(ctx, chf);
                // Partition the walkable surface into simple regions without holes.
                RecastRegion.buildRegions(ctx, chf, bcfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea);
            }
            else if (cfg.partitionType == PartitionType.MONOTONE)
            {
                // Partition the walkable surface into simple regions without holes.
                // Monotone partitioning does not need distancefield.
                RecastRegion.buildRegionsMonotone(ctx, chf, bcfg.borderSize, cfg.minRegionArea, cfg.mergeRegionArea);
            }
            else
            {
                // Partition the walkable surface into simple regions without holes.
                RecastRegion.buildLayerRegions(ctx, chf, bcfg.borderSize, cfg.minRegionArea);
            }

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

            // Create contours.
            ContourSet cset = RecastContour.buildContours(ctx, chf, cfg.maxSimplificationError, cfg.maxEdgeLen, RecastConstants.RC_CONTOUR_TESS_WALL_EDGES);

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

            PolyMesh pmesh = RecastMesh.buildPolyMesh(ctx, cset, cfg.maxVertsPerPoly);

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

            PolyMeshDetail dmesh = RecastMeshDetail.buildPolyMeshDetail(ctx, pmesh, chf, cfg.detailSampleDist, cfg.detailSampleMaxError);

            return(new RecastBuilderResult(this, pmesh, dmesh));
        }
Beispiel #7
0
        /// <summary>
        ///
        /// </summary>
        public void BuildNavigationMesh(ContentManager content)
        {
            NavConfig.CellSize               = 0.3f;
            NavConfig.CellHeight             = 0.2f;
            NavConfig.WalkableSlopeAngle     = 45f;
            NavConfig.WalkableHeight         = (int)Math.Ceiling((2f / NavConfig.CellHeight));
            NavConfig.WalkableClimb          = (int)Math.Floor(0.9f / NavConfig.CellHeight);
            NavConfig.WalkableRadius         = (int)Math.Ceiling(0.6f / NavConfig.CellSize);
            NavConfig.MaxEdgeLen             = (int)(12f / NavConfig.CellSize);
            NavConfig.MaxSimplificationError = 1.3f;
            NavConfig.MinRegionArea          = (int)8 * 8;
            NavConfig.MergeRegionArea        = (int)20 * 20;
            NavConfig.DetailSampleDist       = 6f;
            NavConfig.DetailSampleMaxError   = 1f;
            NavConfig.MaxVertsPerPoly        = 3;


            var indices  = new List <int>();
            var vertices = new List <Vector3>();

            /*
             * foreach ( var factory in Nodes ) {
             *      if (!string.IsNullOrWhiteSpace(factory.Model.ScenePath)) {
             *
             *              var scene = content.Load<Scene>( factory.Model.ScenePath );
             *
             *              var nodeCount = scene.Nodes.Count;
             *
             *              var worldMatricies = new Matrix[nodeCount];
             *
             *              scene.ComputeAbsoluteTransforms( worldMatricies );
             *
             *              for ( int i=0; i<scene.Nodes.Count; i++) {
             *
             *                      var worldMatrix = worldMatricies[i] * factory.WorldMatrix;
             *
             *                      var node = scene.Nodes[i];
             *
             *                      if (node.MeshIndex<0) {
             *                              continue;
             *                      }
             *
             *                      var mesh		=	scene.Meshes[ node.MeshIndex ];
             *
             *                      indices.AddRange( mesh.GetIndices( vertices.Count ) );
             *
             *                      vertices.AddRange( mesh.Vertices.Select( v1 => Vector3.TransformCoordinate( v1.Position, worldMatrix ) ) );
             *              }
             *      }
             * }
             */


            var rcmesh = new RecastMesh();

            rcmesh.Indices  = indices.ToArray();
            rcmesh.Vertices = vertices.ToArray();
            var context = new BuildContext(false);

            SourceNavigationMesh = rcmesh;

            NavigationMesh = RecastBuilder.BuildNavigationMesh(rcmesh, NavConfig, context, true);


            var cs = NavConfig.CellSize;
            var ch = NavConfig.CellHeight;
            var t  = NavigationMesh;

            navVertices = new Vector3[t.VerticesCount];
            navIndices  = new int[t.PolysCount * 3];

            Vector3 origin = NavConfig.BMin;

            for (int i = 0; i < t.PolysCount; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    var index = t.Polys[i * 6 + j];
                    navIndices[i * 3 + j] = index;

                    ushort  a      = t.Verts[index * 3];
                    ushort  b      = t.Verts[index * 3 + 1];
                    ushort  c      = t.Verts[index * 3 + 2];
                    Vector3 vertex = origin + new Vector3(a * cs, b * ch, c * cs);
                    navVertices[index] = vertex;
                }
            }
        }