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