ikpil / DotRecast

DotRecast - a port of Recast & Detour, Industry-standard navigation mesh toolset for .NET, C#, Unity3D, games, servers
zlib License
560 stars 72 forks source link

Question: Mesh DetaiIs are null after mesh generation #59

Open lehmamic opened 8 months ago

lehmamic commented 8 months ago

Hi,

I'm playing around with OpenGL and trying to generate a navMesh with DotRecast. I'm a bit stuck because the detail mesh is always null after mesh generation.

I'm using a left hand coord system: Left hand coord system

Im generating terrain mesh from a hightmap. The mesh is squared with a length of 800.0f (-400.0f to 400.0f) and a height between 0.0f and 40.0f. It has a grid of 256x256 cells divided into two triangular polygons each.

Terrain Mesh

I'm converting my mesh to a right hand system before I pass it to the Geo provider:

public static class MeshConverter
{
    public static MeshData<VertexPositionNormalTexture, uint> ConvertMeshToRightHandSystem(this MeshData<VertexPositionNormalTexture, uint> meshData)
    {
        var convertedVertices = new VertexPositionNormalTexture[meshData.Vertices.Length];
        for (int i = 0; i < meshData.Vertices.Length; i++)
        {
            var vertex = meshData.Vertices[i];
            // Swap X and Z for position and normal to convert the mesh for Recast
            var newPosition = new Vector3D<float>(vertex.Position.Z, vertex.Position.Y, vertex.Position.X);
            var newNormal = new Vector3D<float>(vertex.Normal.Z, vertex.Normal.Y, vertex.Normal.X);
            convertedVertices[i] = new VertexPositionNormalTexture(newPosition, newNormal, vertex.TexCoords);
        }

        // The order of indices might need to be adjusted to correct the winding order.
        // Since we have swapped axes, the orientation of triangles could be affected.
        // For this specific case (just axis swap), it might not be necessary, but it should be tested.
        var convertedIndices = new uint[meshData.Indices.Length];
        for (int i = 0; i < meshData.Indices.Length; i += 3)
        {
            // Directly copy the indices as no direct impact on winding order is expected
            convertedIndices[i] = meshData.Indices[i];
            convertedIndices[i + 1] = meshData.Indices[i + 1];
            convertedIndices[i + 2] = meshData.Indices[i + 2];
        }

        return new MeshData<VertexPositionNormalTexture, uint>(convertedVertices, convertedIndices);
    }
}

And afterwards I try to generate the nav mesh:

        var meshInRightHandSystem = mesh.ConvertMeshToRightHandSystem();
        float[] vertexArray = meshInRightHandSystem.Vertices.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToArray();
        int[] indexArray = meshInRightHandSystem.Indices.Select(i => (int)i).ToArray();

       var geomProvider = new DemoInputGeomProvider(vertexArray, indexArray);

        var partitionType = RcPartition.WATERSHED;
        float tileSize = 800 / 256; // Die Größe eines Tiles, basierend auf der Größe deines Terrains und der Anzahl der Tiles
        float cellSize = tileSize / 2; // Wie detailliert jedes Voxel sein sollte, kleinere Werte führen zu detaillierteren NavMeshes
        float cellHeight = 0.2f; // Die Höhe jedes Voxels, kleinere Werte führen zu einem detaillierteren NavMesh
        float agentHeight = 2.0f; // Die Höhe des Agenten, der das NavMesh nutzen wird
        float agentRadius = 0.6f; // Der Radius des Agenten, der das NavMesh nutzen wird
        float agentMaxClimb = 0.9f; // Die maximale Steigung, die der Agent überwinden kann
        float agentMaxSlope = 45.0f; // Der maximale Neigungswinkel, den der Agent noch begehen kann
        int regionMinSize = 8; // Die minimale Größe einer Region, die noch als begehbar betrachtet wird (in Voxeln)
        int regionMergeSize = 20; // Die minimale Größe von Regionen, die zusammengeführt werden sollen (in Voxeln)
        float edgeMaxLen = 12.0f; // Die maximale Länge der Kanten des NavMeshes (längere Kanten werden aufgeteilt)
        float edgeMaxError = 1.3f; // Der maximale Fehler von Kantenverläufen im NavMesh
        int vertsPerPoly = 6; // Die maximale Anzahl von Vertices pro Polygon
        float detailSampleDist = 6.0f; // Der Abstand für die Detail-Mesh-Sampling, größer als 0 aktiviert das Detail-Mesh
        float detailSampleMaxError = 1.0f; // Der maximale Sampling-Fehler für das Detail-Mesh

        RcConfig recastConfig = new RcConfig(
            true,
            (int)tileSize,
            (int)tileSize,
            borderSize: 0,
            partitionType,
            cellSize,
            cellHeight,
            agentMaxSlope,
            agentHeight,
            agentRadius,
            agentMaxClimb,
            regionMinSize,
            regionMergeSize,
            edgeMaxLen,
            edgeMaxError,
            vertsPerPoly,
            detailSampleDist,
            detailSampleMaxError,
            true,
            true,
            true,
            SampleAreaModifications.SAMPLE_AREAMOD_GROUND,
            true);
        var recastBuilderConfig = new RcBuilderConfig(recastConfig, geomProvider.GetMeshBoundsMin(), geomProvider.GetMeshBoundsMax());

        RcBuilder rcBuilder = new RcBuilder();
        RcBuilderResult rcResult = rcBuilder.Build(geomProvider, recastBuilderConfig);
        RcPolyMesh polyMesh = rcResult.GetMesh();
        for (int i = 0; i < polyMesh.npolys; ++i)
        {
            polyMesh.flags[i] = 1;
        }

        RcPolyMeshDetail polyMeshDetail = rcResult.GetMeshDetail();

The poly mesh detail is always null. What I am doing wrong?

ikpil commented 8 months ago

I'm sorry. I've been busy with work, so I couldn't focus. There's a bundle of code for conversion in UniRecast. Could you please take a look?

If it doesn't work, please let me know.