Search Unity

New NavMesh - how to create rotated LocalNavMeshBuilder [SOLVED]

Discussion in 'Navigation' started by martin-sustek, Jun 13, 2017.

  1. martin-sustek

    martin-sustek

    Joined:
    Jul 16, 2014
    Posts:
    14
    I have LocalNavMeshBuilder on procedurally generated spherical planet using NavMeshSourceTag. NavMeshes are generated correctly on north pole (Y axis pointing up), but not for other positions (differently rotated axes).

    I know that NavMeshSurface can create correct NavMeshes on arbitrary rotated gameobjects, but rotating gameobject with LocalNavMeshBuilder does not work well.

    Should I rotate gameobject with NavMeshSourceTag? It is hardly achieveable for me, as I would need to rotate gameobject and couter-rotate its mesh that I receive from a terrain engine.

    Is there any other way to supply rotation or up direction to LocalNavMeshBuilder or NavMeshSourceTag?

    Thank you for all answers.
     
  2. martin-sustek

    martin-sustek

    Joined:
    Jul 16, 2014
    Posts:
    14
    Update: I've tried rotating object with NavMeshSourceTag and navmesh was always oriented with Y axis at the top, so this is definitely not the solution.

    My question remains: How can I make LocalNavMeshBuilder to make arbitrary rotated navmeshes just as NavMeshSurface does in 3_free_orientation example?
     
  3. adriant

    adriant

    Unity Technologies

    Joined:
    Nov 1, 2016
    Posts:
    69
    Hi! You will need to change the code to set the rotation of the NavMeshData object before building the NavMesh. This means adding something like this
    Code (CSharp):
    1. m_NavMesh.rotation = Quaternion.AngleAxis(41, Vector3.forward);
    any time before NavMeshBuilder.UpdateNavMeshDataAsync(...) or NavMeshBuilder.UpdateNavMeshData(...) are called.

    The NavMeshSurface takes the rotation from its game object when the NavMesh gets built with this call
    Code (CSharp):
    1. var data = NavMeshBuilder.BuildNavMeshData(GetBuildSettings(), sources, sourcesBounds, transform.position, transform.rotation);
    This effectively creates a NavMeshData object, sets its position and up-vector orientation and then calls UpdateNavMeshData(...).

    Please see also the documentation pages for NavMeshData and NavMeshBuilder.BuildNavMeshData .
     
  4. martin-sustek

    martin-sustek

    Joined:
    Jul 16, 2014
    Posts:
    14
    Hi adriant,

    Thank you for your answer. I've tried your proposed solution. I have 5 randomly generated LocalNavMeshBuilders in the scene, and one of them showed generated terrain, but wrongly oriented. See attached screenshot. Should I somehow alter the way terrains are displayed to affect their rotation?

    Other 4 have no terrain displayed at all.

    This is what I've done:
    Code (csharp):
    1.  
    2. void UpdateNavMesh(bool asyncUpdate = false)
    3. {
    4.   NavMeshSourceTag.Collect(ref m_Sources);
    5.   var defaultBuildSettings = NavMesh.GetSettingsByID(0);
    6.   var bounds = QuantizedBounds();
    7.  
    8.   m_NavMesh.rotation = transform.rotation;  // I've added this line
    9.   if (asyncUpdate)
    10.     m_Operation = NavMeshBuilder.UpdateNavMeshDataAsync(m_NavMesh, defaultBuildSettings, m_Sources, bounds);
    11.   else
    12.     NavMeshBuilder.UpdateNavMeshData(m_NavMesh, defaultBuildSettings, m_Sources, bounds);
    13. }
    14.  
    Do you have any clue, what I do wrong?
     

    Attached Files:

  5. adriant

    adriant

    Unity Technologies

    Joined:
    Nov 1, 2016
    Posts:
    69
    When the NavMeshData needs to be aligned with the originating geometry then it has to be added to the NavMesh system with the same position & rotation with which it was built. Try this in your code:
    Code (CSharp):
    1.  
    2.         if (m_NavMesh.rotation != transform.rotation)
    3.         {
    4.             m_NavMesh.rotation = transform.rotation; // I've added this line
    5.             m_Instance.Remove();
    6.             m_Instance = NavMesh.AddNavMeshData(m_NavMesh, m_NavMesh.position, m_NavMesh.rotation);
    7.         }
    8.  
    You get freedom for where to place your NavMesh data in the world. Multiple instances of the same NavMeshData can be used by the NavMesh system in various locations and with whichever orientation you need.
    As a side note, changing the position or rotation of the NavMeshData will trigger a full build of that nav mesh, unlike just moving/changing the bounds which doesn't recompute the nav mesh in unchanged areas.

    Please keep in mind though that the bounds passed to UpdateNavMeshData() are local to m_NavMesh. This means that for the LocalNavMeshBuilder class at least the bounds' center needs to be adjusted. Try adding this in QuantizedBounds():
    Code (CSharp):
    1.  
    2.         if (m_NavMesh)
    3.         {
    4.             var nmMatrix = Matrix4x4.TRS(m_NavMesh.position, m_NavMesh.rotation, Vector3.one);
    5.             center = nmMatrix.inverse.MultiplyPoint(center);   // from world to local space
    6.         }
    7.  
    And make sure to adjust the gizmos' transform accordingly in OnDrawGizmosSelected() with:
    Code (CSharp):
    1.             Gizmos.matrix = Matrix4x4.TRS(m_NavMesh.position, m_NavMesh.rotation, Vector3.one);
     
  6. martin-sustek

    martin-sustek

    Joined:
    Jul 16, 2014
    Posts:
    14
    Thank you adriant, it seems that it solved the issue.
     

    Attached Files:

  7. adriant

    adriant

    Unity Technologies

    Joined:
    Nov 1, 2016
    Posts:
    69
    Great! You're welcome, Martin. I'm glad it helped.