- Home /
 
(Solved) Aligning player to surface while still maintaining look direction
Let's assume I have a sphere that can hover, so it has an offset from the ground. What I want is to simply rotate the sphere to match the normals of whatever is under it on the X and Z-axis, but still be able to rotate it to the direction in which it is travelling on the Y-axis. I have tried a few things that I found here on the forum and [2] seemed promising but unfortunately, it did not work. 
 RaycastHit hit;
 if (Physics.Raycast(body.position, Vector3.down, out hit, 10, layerMask))
 { }   
 
 Quaternion groundTilt = Quaternion.FromToRotation(Vector3.up, hit.normal);
 body.rotation = Quaternion.Euler(0, currentMovementDirection.y, 0);
 body.rotation = groundTilt * body.rotation;
 
               
Here is a diagram of what I want, seen from top and side views. 
references: [1] https://answers.unity.com/questions/1347986/rotating-a-player-to-match-terrain-slope.html [2] https://forum.unity.com/threads/rotating-an-object-along-the-terrains-normal-whilst-looking-at-a-position.93570/
Answer by Namey5 · May 19, 2020 at 11:55 AM
You can use vector projection to find the relative forward vector between the ground's normal and your movement vector;
 if (Physics.Raycast (body.position, Vector3.down, out RaycastHit hit, 10f, layerMask))
 {
     //Up is just the normal
     Vector3 up = hit.normal;
     //Make sure the velocity is normalized
     Vector3 vel = currentMovementDirection.normalized;
     //Project the two vectors using the dot product
     Vector3 forward = vel - up * Vector3.Dot (vel, up);
 
     //Set the rotation with relative forward and up axes
     body.rotation = Quaternion.LookRotation (forward.normalized, up);
 }
 
              Hey there Namey thanks for your answer I've been reading up on your answer and although it seems to be correct I am getting unexpected results. Due to the nature of what I'm trying to do I need to rotate quite slowly.
I have used the following code: 
 Quaternion newRot;
 
 if (Physics.Raycast(body.position, Vector3.down, out RaycastHit hit, 100f, layer$$anonymous$$ask))
 {
    Vector3 up = hit.normal;
    Vector3 vel = current$$anonymous$$ovementDirection.normalized;
    Vector3 forward = vel + up * Vector3.Dot(vel, up);
 
    newRot = Quaternion.LookRotation(forward.normalized, up);
    body.rotation = Quaternion.RotateTowards(body.rotation, newRot, bodyRotationSpeed * Time.deltaTime);
 }
 
                  
 And what is happening is that he moves like Id expect while on a flat surface but when he gets to a ramp he seems to turn in the opposite direction. if you take my diagram from the OP the red dot starts to point down ins$$anonymous$$d of up when entering the ramp. 
Whoops, I accidentally swapped the order of the projection - it was supposed to be a subtraction;
 Vector3 forward = vel - up * Vector3.Dot (vel, up);
 
                   I've also edited the original.
Ahh, of course, I should have thought of that, I thought it was somehow my geometry that was off and was seeing if I could launch the ray diffrently.
Your answer