Search Unity

Rotate to match polygon normal.

Discussion in 'Scripting' started by Dark-Protocol, Mar 23, 2012.

  1. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    I'm doing some sort of a planetary gravity except I don't have planets and my player object (a ball) can step anywhere. The gravity thing works great but I'm having some trouble rotating the camera properly.

    Now what I have is a camera parent object which position (only position) strictly duplicates the player's position. The rotation changes according to the normal of the polygon the player is stepping on.

    I first get the average of the normals, then I use Quaternion.FromToRotation(Vector3.up, avgNormals); to get a rotation which will point with the y away from the normal and then pass it to the camera object (a variable named correctRotation). Then in the camera object I have this: transform.rotation = Quaternion.Lerp(transform.rotation, correctRotation, Time.deltaTime*5);

    This thing works almost great but in some cases I get weird rotations on the Y axis with an unknown to me reason. I've showed this in the video below, because I can't really explain it better.

    http://www.mediafire.com/?22jja5bqb9by46g

    I tried different things so far and none of them had effect. My last try was to put this:
    transform.localRotation.y = 0;
    after the Quaternion.Lerp function.

    I guess I don't fully understand how rotations work in Unity.

    Can I get some assistance with this one?

    Thanks !
     
  2. thellama

    thellama

    Joined:
    Mar 25, 2010
    Posts:
    360
    Have you tried just simply setting the camera partent object's y axis to be the normal angle?

    Code (csharp):
    1. function Update () {
    2. var hit : RaycastHit;
    3. Debug.DrawRay (transform.position, -transform.up * 200, Color.red);
    4. if (Physics.Raycast (transform.position, -transform.up, hit, 200)){
    5.         transform.up = hit.normal;
    6.     }
    7. }
    Put this code on a cube and move it over the surface of a sphere.
     
  3. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    I already tried that before posting. The effect was absolutely the same. I also tried to look at the scene in the editor while playing and see how the camera object's axis changes. it just rotates itself around the y axis (exactly what it looks like in the game)
     
  4. thellama

    thellama

    Joined:
    Mar 25, 2010
    Posts:
    360
    Looks like the track is causing the problem now that I watch the video again. It doesn't do it on the first piece have you looked into that?

    I have an idea for a solution but I want to test it before I throw it out and waist your time.
     
  5. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    It's not the track, it's the rotation. For example if the object has it's transform rotated in world X on 90 degrees and then I try to rotate it locally on it's Z (which after the X rotation has now become the world's Y), the object rotates around it's local Y coordinate. This also happens when I roll the ball on the upside down side of the platforms. The axes get messed up and the camera starts to rotate on it's Y. The problem is that this object is not a child of anything so I can't just set localRotation.y to 0 or localEulerAngles to 0.

    Just sharing my observations if that is of any help :)
     
  6. thellama

    thellama

    Joined:
    Mar 25, 2010
    Posts:
    360
    Can you share a shot of the hierarchy that shows how the camera and it's group are following the ball?

    That might give me some insight on how everything is working.
     
  7. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Yes, of course. I'll just try to recreate it and explain.
    The whole group of game objects is NOT parented to the player. It's completely apart from it, but sticks to it's position using a script.

    Code (csharp):
    1.  
    2.  - BallCamera (this is the object I'm trying to rotate)
    3.          -XGuide (this object rotates around it's local Y axis to achieve horizontal rotation)
    4.                     -YGuide (this object rotates around it's local X axis to achieve vertical rotation)
    5.                              -Main Camera (the camera itself it's away from the YGuide so I get an orbit effect)
    6.  
    I need to keep the XGuide and YGuide apart and not merge their functions into one object. I collect important information from both of them separately.
     
    Last edited: Mar 24, 2012
  8. ciaravoh

    ciaravoh

    Joined:
    Dec 16, 2009
    Posts:
    252
    Have you checked if some script is attached to the camera and gives the WoW kind of camera movement ? Whenever an object is place between the target and the camera, the camera orbit to avoid the obstacle... it looks like this kind of script (standard asset)
     
  9. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Nah. I do have a script that casts a ray from the camera and repositions the camera if there's an obstacle in the way, but this cannot be the problem.

    Here, let's summarize my code so everyone can test and see what happens:

    Code (csharp):
    1.  
    2. function OnCollisionStay(col : Collision){
    3.  
    4. //Let's get the average of the collision normals
    5. var avgNormals : Vector3;
    6.     for(i=0; i<col.contacts.length; i++){
    7.         avgNormals += col.contacts[i].normal;
    8.     }
    9. avgNormals/=col.contacts.length
    10.  
    11. //Then create a rotation from this
    12. var  correctRotation : Quaternion =  Quaternion.FromToRotation(Vector3.up, avgNormals);
    13.  
    14.  
    15. //And set the rotation
    16. transform.rotation = Quaternion.Lerp(transform.rotation, correctRotation, Time.deltaTime*5);
    17. }
    Note that this is not the real script. In my game, the player object calculates the normals and the rotation and then passes them to the camera object, which rotates itself. However the operations are no different than the ones in my game and you are likely to get the same problem. Try to make a scene similar to mine (from the video) with planes and test it with a cube. It is going to rotate on it's local Y axis at some point. You can also try to print the correctRotation in the console.
     
  10. Aniani

    Aniani

    Joined:
    Mar 17, 2011
    Posts:
    31
    I think the Quaternion.FromToRotation function is a bit misleading in Unity's docs because from what I've found it actually returns the 'rotation movement' to get from one rotation to another, not the final rotation itself. So you might try applying it to the current rotation (kind of like adding vectors to get a new position/direction)

    Code (csharp):
    1.  
    2. // Calculate rotation from the camera's up instead
    3. var rotationAdjustment : Quaternion =  Quaternion.FromToRotation(transform.up, avgNormals);
    4.  
    5. // Apply the adjustment to the current rotation
    6. var correctRotation : Quaternion = rotationAdjustment * transform.rotation;
    7.  
    8. // Smoothly change the rotation towards the correct rotation
    9. transform.rotation = Quaternion.RotateTowards(transform.rotation, correctRotation, rotationSpeed * Time.deltaTime);
    10.  
     
  11. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Hey, thanks for joining ! I tried it and the camera behaves pretty randomly. I tried several variations of your suggestion, but none of them gave a different effect. Did you see the video? The gameobject just cannot rotate itself only around it's X and Z axes. At some point it needs to be rotated on it's Y axis. If this object was a child of another object, I could have done it like this: transform.localEulerAngles.y = 0 (I guess).

    Maybe if we can alter the output from FromToRotation so it doesn't alter the Y rotation, relative to it's coordinate system in anyway.
    ..or just lock the object's local Y rotation axis somehow.
     
  12. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    I still can't solve this problem. And no, what I thought was wrong. Making the rotating camera object a child of another object and modifying it's local rotation DOES NOT work :

    gravityAligner.localRotation = Quaternion.Lerp(gravityAligner.localRotation, correctRotation, Time.deltaTime*5);
    gravityAligner.localEulerAngles.y = 0;


    Is it possible that this is a bug in the Unity engine ?
     
  13. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Sorry, tripple posting but I really need some support. This is going to be one of the main features of our small game and if I can't get it to work, I won't be able to proceed with the development.

    I'm sure, that there's people who have done such things before. I wonder if they've had the same problems...
     
  14. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Does anyone think that the AngleAxis function can be of any use?

    From what I'm reading in the docs, it could do the job but I need to figure out how will I use it in conjunction with the normal rotation.
     
  15. MarioRuiz

    MarioRuiz

    Joined:
    Nov 7, 2009
    Posts:
    161
    Maybe check the normal and make it the upwards of a LookRotation, like

    first do your calculations for the forward direction and then:

    transform.rotation = Quaternion.LookRotation( transform.forward, -hit.normal );

    so upwards would always be radial to the planet...
     
  16. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    Sorry for the tardy reply!
    I tried this before and it gives the same result.
    I'm starting to think that this is impossible to fix.
     
  17. MarioRuiz

    MarioRuiz

    Joined:
    Nov 7, 2009
    Posts:
    161
    Have you tried the rotation on LateUpdate?
     
  18. Dark-Protocol

    Dark-Protocol

    Joined:
    Nov 19, 2011
    Posts:
    279
    yes and it's not any different sadly :(
     
  19. Droedel

    Droedel

    Joined:
    Apr 10, 2012
    Posts:
    1
    This looks exactly like something I'm programming right now. I'm trying to get the player walk on walls in every rotation possible, but I always get issues with the normals. But I was wondering if I could look into your script for reference?