Search Unity

Align mesh with terrain

Discussion in 'World Building' started by Ben_Iyan, May 17, 2018.

  1. Ben_Iyan

    Ben_Iyan

    Joined:
    May 13, 2016
    Posts:
    204
    I followed the example provided by @Jakob_Unity here:

    https://forum.unity.com/threads/navmesh-agent-and-smooth-alignment-with-surface-normals.135964/

    but it doesn't work. Others in the thread have reported success, so I logged the value of the terrain normal and always got (0, 1, 0) - in other words up. Clearly the mesh doesn't need to rotate if it believes that the terrain beneath it is flat, so I must be doing something wrong. I've attached the code here for convenience. This is day three, and I'm running out of hair to pull out, so any help would be great. Thanks.

    Code (CSharp):
    1. // TerrainMover.cs
    2. using UnityEngine;
    3. using System.Collections;
    4. public class TerrainMover : MonoBehaviour {
    5.   public Transform target;
    6.   public Terrain terrain;
    7.   private NavMeshAgent agent;
    8.   private Quaternion lookRotation;
    9.   void Start () {
    10.     agent = GetComponent<NavMeshAgent>();  //< cache NavMeshAgent component
    11.     agent.updateRotation = false;          //< let us control the rotation explicitly
    12.     lookRotation = transform.rotation;     //< set original rotation
    13.   }
    14.   Vector3 GetTerrainNormal () {
    15.     Vector3 terrainLocalPos = transform.position - terrain.transform.position;
    16.     Vector2 normalizedPos = new Vector2(terrainLocalPos.x / terrain.terrainData.size.x,
    17.                                         terrainLocalPos.z / terrain.terrainData.size.y);
    18.     return terrain.terrainData.GetInterpolatedNormal(normalizedPos.x, normalizedPos.y);
    19.   }
    20.   void Update () {
    21.     agent.destination = target.position; //< update agent destination
    22.     Vector3 normal = GetTerrainNormal();
    23.     Vector3 direction = agent.steeringTarget - transform.position;
    24.     direction.y = 0.0f;
    25.     if(direction.magnitude > 0.1f  normal.magnitude > 0.1f) {
    26.       Quaternion qLook = Quaternion.LookRotation(direction, Vector3.up);
    27.       Quaternion qNorm = Quaternion.FromToRotation(Vector3.up, normal);
    28.       lookRotation = qNorm * qLook;
    29.     }
    30.     // soften the orientation
    31.     transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime/0.2f);
    32.   }
    33. }
     
  2. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
    Should you not use terrain.terrainData.size.z there?

    Code (csharp):
    1.  
    2.   Vector2 normalizedPos = new Vector2(terrainLocalPos.x / terrain.terrainData.size.x,                                        terrainLocalPos.z / terrain.terrainData.size.y);
    3.  
     
  3. Ben_Iyan

    Ben_Iyan

    Joined:
    May 13, 2016
    Posts:
    204
    I thought that I had tried changing y to z and got an error but ... no error now. The only change however is that the mesh oscillates very slightly in the x-axis, even though agent.updateRotation = false.

    Love VS, BTW :)
     
  4. LennartJohansen

    LennartJohansen

    Joined:
    Dec 1, 2014
    Posts:
    2,394
    Add a Debug.DrawRay with the normal you get out. to see that you do get the right data.
     
  5. Ben_Iyan

    Ben_Iyan

    Joined:
    May 13, 2016
    Posts:
    204
    @LennartJohansen That was a good idea; the normal always faces up, which is why the vehicle doesn't conform to the slope. I wonder if the code is reading the elevation from a different part of the map (i.e. always flat). If so, it's not obvious why.