Exemplo n.º 1
0
    private static Navmesh GenerateNavmesh()
    {
        #region Generate Neighboring polygon data

        //Then generate neighboring polygon data, by parsing the face list
        MyVector3 <bool> sharedVertex;          //For the current face, what vertices are shared with the other face?
        int sharedVertices;                     //if goes to 2, edge is shared

        for (ushort q = 0; q < faces.Count; q++)
        {
            //Index of face and neighborPoly refer to the same polygon.
            neighborPolys.Add(new MyVector3 <ushort>());
            neighborPolys[q].x = Navmesh.NullIndex;
            neighborPolys[q].y = Navmesh.NullIndex;
            neighborPolys[q].z = Navmesh.NullIndex;

            //Compare this face with every other face
            for (ushort w = 0; w < faces.Count; w++)
            {
                if (w != q)
                {
                    sharedVertices = 0;
                    sharedVertex   = new MyVector3 <bool>();

                    //Go from left to right in the face MyVector3
                    for (int j = 0; j <= 2; j++)
                    {
                        //And compare each index with every other index
                        for (int k = 0; k <= 2; k++)
                        {
                            if (faces[q][j] == faces[w][k])
                            {
                                //If we find a matching index, update stuff (only for the current face, dont bother with other face, can optimise but will be confusing)
                                sharedVertices++;
                                sharedVertex[j] = true;                                 //could break out of the for loop now, as face will not list the same index twice
                            }
                        }
                    }
                    if (sharedVertices > 2)
                    {
                        ReportError("error: more than 2 vertices shared between polys " + q + " and " + w);
                    }

                    //Check if these faces are sharing an edge
                    if (sharedVertices == 2)
                    {
                        //get the Leftmost Right-To-Left Pair in the neighborPolys MyVector3
                        //options are: edge 0-1, 1-2, and 2-0, respectively indexing neighboringPolys. (i.e. if index 1 of neighboring polys is 45, that means that the current polygon and polygon 45 share the edge face[1] <-> face[2]
                        if (sharedVertex[0] == true)
                        {
                            if (sharedVertex[1] == true)
                            {
                                neighborPolys[q][0] = w;                                        //I.e. tell this face's MyVector3 of neighboring polygons that the edge made up by vertices at 0 and 1 is shared between polygon q and w
                            }
                            else
                            {
                                neighborPolys[q][2] = w;
                            }
                        }
                        else
                        {
                            neighborPolys[q][1] = w;
                        }
                    }
                } //End iterating through other faces
            }
        }         //End iterating through each face
        #endregion

        //Now, Load these into Critter AI and create a navmesh
        navData = new NavmeshTileBuildData(maxPolyVerts, maxPolys, maxVertsPerPoly, 0, 0, 0);

        #region LoadBase
        //Get the min and max bounds from the vertex positions
        float lowest;
        float highest;

        //Find the bounds of the mesh. iterate through the x, y and z axes
        for (int axis = 0; axis <= 2; axis++)
        {
            lowest  = UPPER_LIMIT;               //set to inital values that they do not reach
            highest = LOWER_LIMIT;

            //iterate through every vertex to find highest and lowest value of this axis
            for (int i = 0; i < vertices.Count; i++)
            {
                if (vertices[i][axis] < lowest)
                {
                    lowest = vertices[i][axis];
                }

                if (vertices[i][axis] > highest)
                {
                    highest = vertices[i][axis];
                }
            }

            if (axis == 0)            //x
            {
                boundsMin.x = lowest;
                boundsMax.x = highest;
            }
            else if (axis == 1)
            {
                boundsMin.y = lowest;
                boundsMax.y = highest;
            }
            else if (axis == 2)
            {
                boundsMin.z = lowest;
                boundsMax.z = highest;
            }
        }

        bool sucess;
        sucess = navData.LoadBase(tileX, tileZ, tileLayer, tileUserId, boundsMin, boundsMax, xzCellSize, yCellSize, walkableHeight, walkableRadius, walkableStep, bvTreeEnabled);
        if (!sucess)
        {
            ReportError("Error, LoadBase returned false");
        }

        #endregion

        #region LoadPolys
        vertCount = vertices.Count;
        polyCount = faces.Count;

        //Convert vertices from world space to grid space
        polyVerts = new ushort[vertCount * 3];

        for (int i = 0; i < vertCount; i++)
        {
            polyVerts[3 * i + 0] = (ushort)Math.Round((vertices[i].x - boundsMin.x) / xzCellSize);
            polyVerts[3 * i + 1] = (ushort)Math.Round((vertices[i].y - boundsMin.y) / yCellSize);
            polyVerts[3 * i + 2] = (ushort)Math.Round((vertices[i].z - boundsMin.z) / xzCellSize);
        }

        //build polys array (http://www.critterai.org/projects/cainav/doc/html/B8C2F0F4.htm)
        polys = new ushort[6 * polyCount];
        int ind    = 0;
        int faceNo = 0;

        while (faceNo < polyCount)
        {
            polys[ind + 0] = faces[faceNo].x;
            polys[ind + 1] = faces[faceNo].y;
            polys[ind + 2] = faces[faceNo].z;

            polys[ind + 3] = neighborPolys[faceNo].x;
            polys[ind + 4] = neighborPolys[faceNo].y;
            polys[ind + 5] = neighborPolys[faceNo].z;

            ind += 6;
            faceNo++;
        }

        //Fill polyflags array with default flags
        polyFlags = new ushort[polyCount];
        for (int i = 0; i < polyCount; i++)
        {
            polyFlags[i] = 1;                           //custom user flag
        }
        //Fill polyAreas array
        polyAreas = new byte[polyCount];
        for (int i = 0; i < polyCount; i++)
        {
            polyAreas[i] = 1;
        }

        sucess = navData.LoadPolys(polyVerts, vertCount, polys, polyFlags, polyAreas, polyCount);

        if (!sucess)
        {
            ReportError("Error, LoadPolys returned false");
        }

        #endregion

        //Build the Navmesh using the navData
        NavStatus status = Navmesh.Create(navData, out navmesh);

        if (status != NavStatus.Sucess)
        {
            ReportError("Navmesh build status was " + status.ToString());
        }

        return(navmesh);
    }
Exemplo n.º 2
0
        /// <summary>
        /// Creates a standard <see cref="NavmeshTileBuildData"/> object from the provided
        /// parameters.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Errors will be logged to the build context.
        /// </para>
        /// </remarks>
        /// <param name="tx">The x-index of the tile.</param>
        /// <param name="tz">The z-index of the tile.</param>
        /// <param name="polyMesh">The polygon mesh data.</param>
        /// <param name="detailMesh">The detail mesh data. (Optional)</param>
        /// <param name="connections">The off-mesh connections. (Null allowed.)</param>
        /// <param name="bvTreeEnabled">True if bounding volumes should be generated.</param>
        /// <param name="context">The build context.</param>
        /// <returns>The tile build data, or null on error.</returns>
        public static NavmeshTileBuildData GetBuildData(BuildContext context
                                                        , int tx, int tz
                                                        , PolyMeshData polyMesh, PolyMeshDetailData detailMesh
                                                        , ConnectionSet connections
                                                        , bool bvTreeEnabled)
        {
            if (context == null)
            {
                // Silent.
                return(null);
            }

            Vector3[] verts   = null;
            float[]   radii   = null;
            byte[]    dirs    = null;
            byte[]    areas   = null;
            ushort[]  flags   = null;
            uint[]    userIds = null;

            Vector3 bmin = polyMesh.boundsMin;
            Vector3 bmax = polyMesh.boundsMax;

            int connCount = (connections == null)
                ? 0
                : connections.GetConnections(bmin.x, bmin.z, bmax.x, bmax.z
                                             , out verts, out radii, out dirs, out areas, out flags, out userIds);

            NavmeshTileBuildData result = new NavmeshTileBuildData(
                polyMesh.vertCount
                , polyMesh.polyCount
                , polyMesh.maxVertsPerPoly
                , (detailMesh == null ? 0 : detailMesh.vertCount)
                , (detailMesh == null ? 0 : detailMesh.triCount)
                , connCount);

            if (!result.LoadBase(tx, tz, 0, 0
                                 , polyMesh.boundsMin
                                 , polyMesh.boundsMax
                                 , polyMesh.xzCellSize
                                 , polyMesh.yCellSize
                                 , polyMesh.walkableHeight
                                 , polyMesh.walkableRadius
                                 , polyMesh.walkableStep
                                 , bvTreeEnabled))
            {
                context.LogError("Base data load failed. Bad configuration data or internal error."
                                 , null);
                return(null);
            }

            if (!result.LoadPolys(polyMesh.verts
                                  , polyMesh.vertCount
                                  , polyMesh.polys
                                  , polyMesh.flags
                                  , polyMesh.areas
                                  , polyMesh.polyCount))
            {
                context.LogError("Polygon load failed. Bad mesh data or internal error.", null);
                return(null);
            }

            if (detailMesh != null)
            {
                if (!result.LoadDetail(detailMesh.verts
                                       , detailMesh.vertCount
                                       , detailMesh.tris
                                       , detailMesh.triCount
                                       , detailMesh.meshes
                                       , detailMesh.meshCount))
                {
                    context.LogError("Detail load failed. Bad mesh data or internal error.", null);
                    return(null);
                }
            }

            if (connCount > 0)
            {
                if (!result.LoadConns(verts, radii, dirs, areas, flags, userIds, connCount))
                {
                    context.LogError("Off-mesh connection load failed. Bad data or internal error."
                                     , null);
                    return(null);
                }
            }

            return(result);
        }