Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Need help fixing align to spherical surface script

Discussion in 'Scripting' started by Rusoski, Sep 13, 2017.

  1. Rusoski

    Rusoski

    Joined:
    Nov 6, 2013
    Posts:
    63
    Good day community!

    I got this script attached to the player:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class SurfaceAlignment : MonoBehaviour {
    4.  
    5.     bool allowAlign = true;
    6.     float alignSpeed = 10f;
    7.  
    8.     void Start () {
    9.        
    10.     }
    11.    
    12.     void FixedUpdate () {
    13.         foreach (GameObject go in GameObject.FindGameObjectsWithTag("Planet"))
    14.         {
    15.             float atmosthereRadius = go.GetComponent<Planet>().atmosphere;
    16.  
    17.             float xDist = go.transform.position[0] - transform.position[0];
    18.             float yDist = go.transform.position[1] - transform.position[1];
    19.             float zDist = go.transform.position[2] - transform.position[2];
    20.  
    21.             float distSquared = Mathf.Pow(xDist, 2) + Mathf.Pow(yDist, 2) + Mathf.Pow(zDist, 2);
    22.  
    23.             float dist = Mathf.Sqrt(distSquared);
    24.  
    25.             if (allowAlign)
    26.             {
    27.                 if (dist <= atmosthereRadius)
    28.                 {
    29.                     Vector3 targetPoint = go.transform.position - transform.position;
    30.                     Quaternion targetRotation = Quaternion.LookRotation(targetPoint);
    31.                     transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * alignSpeed);
    32.                 }
    33.                 else
    34.                 {
    35.                     Vector3 targetPoint = new Vector3(0f, 0f, 0f);
    36.                     Quaternion targetRotation = Quaternion.LookRotation(targetPoint, Vector3.up);
    37.                     transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * alignSpeed);
    38.                 }
    39.             }
    40.         }
    41.     }
    42. }
    What this code does is that when the player aproaches a sphere with the tag "Planet" in a range, it's mesh is aligned to the vector from the center of the sphere to the player position, but problem here is that instead of landing on feet, the player lands on his belly, this means that instead of being aligned over the Y axis, the playes is aligned over the Z Axis. I just do not have enough brain to fix this.
     
  2. Dave-Carlile

    Dave-Carlile

    Joined:
    Sep 16, 2012
    Posts:
    967
    Not an answer to your question, but distance can be calculated like this:

    Code (csharp):
    1. float distance = (go.transform.position - transform.position).magnitude;
    or

    Code (csharp):
    1. float distance = Vector3.Distance(go.transform.position, transform.position);
    That will simplify your code quite a bit.

    As far as the orientation being off, how is your model aligned in its local space? You may just need to add 90 degrees or something, or use a different Up vector when calling LookRotation?
     
    Rusoski likes this.
  3. Rusoski

    Rusoski

    Joined:
    Nov 6, 2013
    Posts:
    63
    Thank you, I will consider this, I am using a Primitive Cube created inside Unity
     
  4. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    Couple options here:

    1) Use a state machine. If the player falls, switch the camera's reference point to something else (or even just null) where it can lazily drift around with a mournful "awwww" audio clip.

    2) Use the ground surface as the camera's reference point. You have both the surface position + normal. Offset up along the normal to use as the camera's look-at position.

    3) Use a variation of the above and blend together the reference points to set the camera's final reference point.

    4) Look at the Cinemachine tool which can handle this stuff for you (I haven't personally used it yet, so I can't quite tell you how to use it).
     
    Rusoski likes this.
  5. Rusoski

    Rusoski

    Joined:
    Nov 6, 2013
    Posts:
    63
    Thank you, but to be honest I don't understand this
     
  6. Dave-Carlile

    Dave-Carlile

    Joined:
    Sep 16, 2012
    Posts:
    967
    So... how do you know if the player has landed on his feet or his belly? :)
     
    Rusoski likes this.
  7. Rusoski

    Rusoski

    Joined:
    Nov 6, 2013
    Posts:
    63
    Because of the Local Axis, Z Axis should be Front-Back, Y Axis should be Up-Down and X Axis should be Left-Right, Z positive gets alignes to the vector so it lands with the belly, it should be aligned over Y negative (Down) Axis
     
  8. unit_nick

    unit_nick

    Joined:
    Jul 15, 2017
    Posts:
    23
    Are you sure the atmosthereRadius is large enough that he can stand? Maybe the distance is always greater causing him to face the center?
     
  9. Rusoski

    Rusoski

    Joined:
    Nov 6, 2013
    Posts:
    63
    Yes, I can see the rotation between the outer space orbit and inside atmosphere.

    Also I have solved the issue, kind of, instead of adding this script to the player, I created an Empty Transform, then I parented the camera to the transform and added a rotation script to the camera, made some adjustments to the rotation script, then I just copied the location of the player over the Empty Transform and then copied the rotation of the Empty Transform to the player and it works, problem is that I can not rotate the player over it's Y Axis, I still have to solve that and I have figured out what the problem is but I do not know what is causing it, I currently have this thing:

    Code (CSharp):
    1. Vector3 targetPoint = go.transform.position - transform.position;
    2. Quaternion targetRotation = Quaternion.LookRotation(targetPoint);
    3. transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * alignSpeed);
    What I did is to override it with:

    Code (CSharp):
    1. Vector3 v = go.transform.position - transform.position;
    2. Quaternion q = Quaternion.FromToRotation(-transform.up, v);
    3. transform.rotation = q * transform.rotation;
    And it works almost perfect, problem is that the transition between the 2 rotation is instant, there is no smooth transition, so I changed the last line and in result it looks like:

    Code (CSharp):
    1. Vector3 v = go.transform.position - transform.position;
    2. Quaternion q = Quaternion.FromToRotation(-transform.up, v);
    3. transform.rotation = Quaternion.Slerp(transform.rotation, q, Time.deltaTime * alignSpeed);
    But Quaternion.Lerp() and Quaternion.Slerp() causes a weird issue, instead of aligning to the surface based on the position over the planet, it sit still over a constant direction, this means that the vector always points to somewhere and never changes, no matter the position of the player over the planet.