Search Unity

Align the mesh (child object) with terrain normals?

Discussion in 'Scripting' started by skinwalker, Jan 29, 2018.

  1. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    305
    Hey,

    I have read and tried many of the suggestions, but I am stuck with this for over 3 days. I have a parent game object that has a navmesh agent and a child object that contains the rig + skinned mesh. So I would like to rotate that child container with the terrain normal as the navmesh agent is moving, but nothing I've tried offers smooth rotation. I only want to rotate the character up and down as it's climbing a hill or going downhills. So far I have this, which is rotating the child along X Y Z and it's not smooth, really glitching as the character is moving fast (it's a deer).

    Code (CSharp):
    1.  public void Align()
    2.         {
    3.             RaycastHit hit;
    4.             Vector3 theRay = transform.TransformDirection(Vector3.down);
    5.  
    6.             if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 3, transform.position.z),
    7.                 theRay, out hit, 20, _terrainLayer))
    8.             {
    9.                 Vector3 normal = hit.normal;
    10.  
    11.  
    12.                 transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
    13.  
    14.             }
    15.         }
    I am following this tutorial to set up the navmesh agent and turning with root motion.

    Any suggestions would be great, I am really stuck with this. At this point I am really wondering if that's possible to do in Unity, I have read over 30 posts and tried lots of things and nothing seems to be smoothly lerping the rotation without making the npc go crazy while rotating.
     
    Last edited: Jan 29, 2018
  2. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    287
    You are doing it right, the only thing you would need to add is the smoothing between current rotation and target rotation (terrain normal).
    Code (CSharp):
    1. private Quaternion targetRotation
    2. public void Align()
    3.         {
    4.             RaycastHit hit;
    5.             Vector3 theRay = transform.TransformDirection(Vector3.down);
    6.             if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 3, transform.position.z),
    7.                 theRay, out hit, 20, _terrainLayer))
    8.             {
    9.                 Vector3 normal = hit.normal;
    10.                targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
    11.             }
    12.         }
    13.  
    14. void Update(){
    15.     transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 0.1f/Time.deltaTime);
    16.  
    17. }
    I'm not sure if 0.1f/deltaTime is the right way to do athe smoothing in 0.1 sec, it might be the other way around deltaTime/0.1f
     
    twobob and skinwalker like this.
  3. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    have you tried calling this in LateUpdate?

    also, total aside, like 4 is the same as "-transform.up"
     
  4. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    305
    Time.DeltaTime / 0.1f is giving a nice result, except the child's forward rotation doesn't follow the agent's rotation (attached to it's parent) so the deer looks to the left while moving forward. It's something like this:

     
    Last edited: Jan 29, 2018
  5. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    305
    I modified some of the things and now it's looking better. I am still experimenting where to call the Align method - Update, LateUpdate or FixedUpdate. It seems like FixedUpdate gives the best result, but I'm not sure, the difference is really minor and it's hard to compare.

    Code (CSharp):
    1.  private void Align()
    2.         {
    3.             RaycastHit hit;
    4.             Vector3 theRay = -transform.up;
    5.  
    6.  
    7.             if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 3, transform.position.z),
    8.                 theRay, out hit, 20, _terrainLayer))
    9.             {
    10.  
    11.                 Quaternion  targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.parent.rotation;
    12.  
    13.                 transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime / 0.15f);
    14.             }
    15.         }
     
    Hoorza likes this.
  6. whileBreak

    whileBreak

    Joined:
    Aug 28, 2014
    Posts:
    287
    That much i can't help, maybe try replacing
    Code (CSharp):
    1.    targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
    with this
    Code (CSharp):
    1.    targetRotation = Quaternion.Euler(hit.normal);
    If that doesn't work you can try proyecting the NM Agent's forward against the plain with normal transform.up and make a look at

    Code (CSharp):
    1. void Update(){
    2.  
    3. transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 0.1f/Time.deltaTime);
    4. Vector3 for = Vector3.ProyectOnPlane(transform.parent.forward,transform.up).normalized;
    5. transform.LookAt(transform.position + for);
    6.  
    7. }
     
  7. Hoorza

    Hoorza

    Joined:
    May 8, 2016
    Posts:
    20
    Hey @skinwalker . I have used your code (exactly as it is here in your last comment) as I was struggling with the same problem. It works like a charm for me. I have tried in the Update() and in the FixedUpdate() too. There is no visible difference for me. My character has no animations yet. Just the mesh, speed is 2 for the navMesh agent and everything seems ok. Maybe your problem comes from the animator as the code seems to be doing exactly what it should. Thanks a lot! I was trying to make that bloody sheep walk properly for the past two days. Cheerio!!
     
    skinwalker likes this.
  8. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    305
    Good to see it's working for your project. I think my problem was because I didn't properly order the hierarchy of that object and bones were rotated weirdly, now this problem is fixed and working well with the code I posted.
     
    Hoorza likes this.