Align the mesh (child object) with terrain normals?

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).

 public void Align()
        {
            RaycastHit hit;
            Vector3 theRay = transform.TransformDirection(Vector3.down);

            if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 3, transform.position.z),
                theRay, out hit, 20, _terrainLayer))
            {
                Vector3 normal = hit.normal;


                transform.rotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;

            }
        }

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.

You are doing it right, the only thing you would need to add is the smoothing between current rotation and target rotation (terrain normal).

private Quaternion targetRotation
public void Align()
        {
            RaycastHit hit;
            Vector3 theRay = transform.TransformDirection(Vector3.down);
            if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 3, transform.position.z),
                theRay, out hit, 20, _terrainLayer))
            {
                Vector3 normal = hit.normal;
               targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
            }
        }

void Update(){
    transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 0.1f/Time.deltaTime);

}

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

2 Likes

have you tried calling this in LateUpdate?

also, total aside, like 4 is the same as “-transform.up”

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:

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.

 private void Align()
        {
            RaycastHit hit;
            Vector3 theRay = -transform.up;


            if (Physics.Raycast(new Vector3(transform.position.x, transform.position.y + 3, transform.position.z),
                theRay, out hit, 20, _terrainLayer))
            {

                Quaternion  targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.parent.rotation;

                transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime / 0.15f);
            }
        }
1 Like

That much i can’t help, maybe try replacing

   targetRotation = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;

with this

   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

void Update(){

transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, 0.1f/Time.deltaTime);
Vector3 for = Vector3.ProyectOnPlane(transform.parent.forward,transform.up).normalized;
transform.LookAt(transform.position + for);

}

Hey @skinwalker_1 . 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!!

2 Likes

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.

1 Like