Hello!
I have been browsing the Unity answers for 3 days but have not gotten any results that are usable.
I have a 3rd person character controller that will rotate the character to look in the direction the camera is facing (this works).
I also have a “terrain stick” algorithm that rotates the character to match the angle that the terrain is at (this works).
However, when I combine the two, it most certainly doesn’t work. I was wondering if anyone might be able to toss an assist on this (it is driving me batty!)
I am using a character controller with no rigidbody
The movement script is applied to the “Player” object
Hierarchy:
Any other help would be greatly appreciated! (entire post of pictures: Unity Answers Help - Rotation - Album on Imgur )
[Header("Rotation Type B")]
public Transform backLeft;
public Transform backRight;
public Transform frontLeft;
public Transform frontRight;
public RaycastHit lr;
public RaycastHit rr;
public RaycastHit lf;
public RaycastHit rf;
public Vector3 upDir;
void Update()
{
//Movement - This all works with no issue
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
float moveDelta = Mathf.Clamp01(Mathf.Abs(h) + Mathf.Abs(v));
var moveInput = new Vector3(h, 0, v).normalized;
var moveDir = cameraController.PlanarRotation * moveInput; //Gives camera forward
GroundCheck();
transform.position += moveDir * moveSpeed * Time.deltaTime;
Vector3 velocity = moveDir * moveSpeed;
if(isGrounded) // Applying gravity, works fine
{
ySpeed = -0.5f;
}
else
{
ySpeed += Physics.gravity.y * Time.deltaTime;
}
velocity.y = ySpeed;
charController.Move(velocity * Time.deltaTime);
//Rotation - This is where things are getting fun
// Calculate rotation to get character to look in camera forward
if (moveDelta > 0)
{
targetRotation = Quaternion.LookRotation(moveDir);
}
//Vector3 down = transform.TransformDirection(Vector3.down);
Vector3 down = Vector3.down;
//This gives the proper Y rotation to make the character look in the direction the camera is facing
facingRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSmoothing * Time.deltaTime);
//This works in isolation
//transform.rotation = facingRotation;
// see: https://imgur.com/pkT4E2n , https://imgur.com/miMeqlo
//More specific raycasting for better terrain sticking
Vector3 down = transform.TransformDirection(Vector3.down); //Have used Vector3.down as well
Physics.Raycast(backLeft.position, down, out lr, 10f, groundCheckLayerMask);
Physics.Raycast(backRight.position, down, out rr, 10f, groundCheckLayerMask);
Physics.Raycast(frontLeft.position, down, out lf, 10f, groundCheckLayerMask);
Physics.Raycast(frontRight.position, down, out rf, 10f, groundCheckLayerMask);
Debug.DrawRay(rr.point, Vector3.down, Color.green);
Debug.DrawRay(lr.point, Vector3.down, Color.green);
Debug.DrawRay(lf.point, Vector3.down, Color.green);
Debug.DrawRay(rf.point, Vector3.down, Color.green);
Vector3 a = rr.point - lr.point;
Vector3 b = rf.point - rr.point;
Vector3 c = lf.point - rf.point;
Vector3 d = rr.point - lf.point;
// Get the normal at each corner
Vector3 crossBA = Vector3.Cross(b, a);
Vector3 crossCB = Vector3.Cross(c, b);
Vector3 crossDC = Vector3.Cross(d, c);
Vector3 crossAD = Vector3.Cross(a, d);
// Calculate composite normal
upDir = (crossBA + crossCB + crossDC + crossAD).normalized;
Vector3 upVector = Vector3.Lerp(transform.up, upDir, Time.deltaTime);
if (isGrounded)
uprightRotation = Quaternion.FromToRotation(Vector3.up, upVector);
else
uprightRotation = Quaternion.identity;
//This works in isolation
//transform.rotation = uprightRotation;
// see: https://imgur.com/ZzqlvhC , https://imgur.com/UtVUWSX
// This doesn't work, it spams between two rotations
finalRotation = uprightRotation * facingRotation;
//transform.rotation = finalRotation;
// see: https://imgur.com/eae7Uet , https://imgur.com/OScvAix and https://imgur.com/gLa93KM , https://imgur.com/fhllUQe
// This doesnt work, is just bad, have learned lesson
//Figure out a way to combine upright and facing
//finalRotation = facingRotation;
//finalRotation.x = uprightRotation.x;
//finalRotation.z = uprightRotation.z;
//transform.rotation = finalRotation;
//THIS DIDNT WORK BUT IT IS A NEW STEP
Vector3 newPos;
Vector3 normal = upVector;
curNormal = Vector3.Lerp(curNormal, normal, 2 * Time.deltaTime);
newPos = moveDir;
newPos.y = 0;
// Doesn't work, character follows camera facing while moving, snaps to the left when at rest.
// Does not follow terrain
finalRotation = Quaternion.FromToRotation(Vector3.up, curNormal);
finalRotation = finalRotation * Quaternion.FromToRotation(Vector3.forward, newPos);
// transform.rotation = finalRotation;
// see: https://imgur.com/AudyNW3 , https://imgur.com/AKegU8m
// Doesn't work - Character snaps to terrain, but doesn't rotate towards camera forward
finalRotation = uprightRotation * Quaternion.Euler(0, facingRotation.y, 0);
//transform.rotation = finalRotation;
// see: https://imgur.com/DDqfHx6 , https://imgur.com/TILrSNV
// Doesn't work -- character jitters, is never looking at facing, sometimes upside down
transform.rotation = facingRotation;
transform.rotation = uprightRotation * transform.rotation;
// see: https://imgur.com/OCGDcn2 , https://imgur.com/Igcy5rp
animator.SetFloat(Words.moveAmount.ToString(), moveDelta, 0.2f, Time.deltaTime);
}