Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I dynamically create an initial DtVoxelFile / DtDynamicNavMesh? #87

Open
bryanedds opened this issue Feb 23, 2025 · 3 comments
Open

Comments

@bryanedds
Copy link

bryanedds commented Feb 23, 2025

Here's the code I'm currently modifying in an attempt to go from using a static DtNavMesh to DtDynamicNavMesh (F#) -

https://github.com/bryanedds/Nu/blob/nav-dynamic/Nu/Nu/World/WorldScreen.fs#L458-L494

            // attempt to execute 3d navigation mesh construction steps
            match geomProviderOpt with
            | Some geomProvider ->
                let rcConfig =
                    RcConfig
                        (true, 32, 32, 1,
                         config.PartitionType,
                         config.CellSize, config.CellHeight,
                         config.AgentSlopeMax, config.AgentHeight, config.AgentRadius, config.AgentClimbMax,
                         single config.RegionSizeMin, single config.RegionSizeMerge,
                         config.EdgeLengthMax, config.EdgeErrorMax,
                         config.VertsPerPolygon, config.DetailSampleDistance, config.DetailSampleErrorMax,
                         config.FilterLowHangingObstacles, config.FilterLedgeSpans, config.FilterWalkableLowHeightSpans,
                         SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true)
                let rcBuilderConfig = RcBuilderConfig (rcConfig, geomProvider.GetMeshBoundsMin (), geomProvider.GetMeshBoundsMax ())
                let rcBuilder = RcBuilder ()
                let rcBuilderResult = rcBuilder.Build (geomProvider, rcBuilderConfig, true) // NOTE: keeping intermediate results now! TODO: P0: try to get rid of any unnecessary intermediate results data!
                if notNull rcBuilderResult.MeshDetail then // NOTE: not sure why, but null here seems to be an indication of nav mesh build failure.
                    let navBuilderResultData = NavBuilderResultData.make rcBuilderResult
                    let voxelFile = DtVoxelFile.From (rcConfig, List [rcBuilderResult])
                    let dtNavMesh = DtDynamicNavMesh voxelFile
                    dtNavMesh.Build Task.Factory |> ignore<bool>
                    let dtQuery = DtNavMeshQuery (dtNavMesh.NavMesh ())
                    Some (navBuilderResultData, dtNavMesh, dtQuery)

                    //let dtCreateParams = DemoNavMeshBuilder.GetNavMeshCreateParams (geomProvider, config.CellSize, config.CellHeight, config.AgentHeight, config.AgentRadius, config.AgentClimbMax, rcBuilderResult)
                    //match DtNavMeshBuilder.CreateNavMeshData dtCreateParams with
                    //| null -> None // some sort of argument issue
                    //| dtMeshData ->
                    //    DemoNavMeshBuilder.UpdateAreaAndFlags dtMeshData |> ignore<DtMeshData> // ignoring flow-syntax
                    //    let dtNavMesh = DtNavMesh ()
                    //    if dtNavMesh.Init (dtMeshData, 6, 0) = DtStatus.DT_SUCCESS then // TODO: introduce constant?
                    //        let dtQuery = DtNavMeshQuery dtNavMesh
                    //        Some (navBuilderResultData, dtNavMesh, dtQuery)
                    //    else None

                else None

The issue appears to be that rcBuilderResult.MeshDetail is always null and thus I can't proceed.

All of the example code I find merely loads the data from a file on disk but doesn't seem to show how to create that file on disk in the first place :) Here I'm just attempting to create the whole thing dynamically at runtime, but if using DtDynamicNavMesh means I have to go to disk temporarily, I'm willing to do that too. I just need to know how to get my initial static scene that I build in my custom engine's editor into a DtDynamicNavMesh. Currently I have no way to proceed other than reversing the intent from reading lots of Dotrecast and trial and error.

@bryanedds
Copy link
Author

I added a link to the pasted code if you need additional context to answer this question easily. Thanks for whatever help you can find time to provide! ❤

@bryanedds bryanedds changed the title How do I actually create an initial DtVoxelFile / DtDynamicNavMesh? How do I dynamically create an initial DtVoxelFile / DtDynamicNavMesh? Feb 27, 2025
@ikpil
Copy link
Owner

ikpil commented Mar 2, 2025

If I understand correctly, the following code for Copy(), Load(), and Save() should be helpful:

  • DynamicUpdateSampleTool.Copy(), Load(), Save()
  • There is code for importing a tile mesh into a dynamic navmesh.
  • There is code for saving the dynamic navmesh to a voxel file.

@bryanedds
Copy link
Author

Okay, so I seem to have gotten normal behavior back again with the dynamic mesh, mostly by taking a look into said Copy function and the code that utilizes it -

Here's the code now -

https://github.com/bryanedds/Nu/blob/540f57a677e6d578a67eb9f21a67b1d663d5b344/Nu/Nu/World/WorldScreen.fs#L459-L504

And here are the default navigation parameters I used -

https://github.com/bryanedds/Nu/blob/nav-dynamic/Nu/Nu/World/WorldPrelude.fs#L102-L120

This API definitely has very few guardrails and a lot of trial-and-error, tuning, and just plain luck was required to get it this far. Hopefully the code and settings I've linked to will help someone in the future!

Since there's a lot more left to do, I'll leave this thread open for further questions as I proceed, then close when everything working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants