Rotate to match polygon normal.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

17. MarioRuiz

Joined:
Nov 7, 2009
Posts:
161
Have you tried the rotation on LateUpdate?

18. Dark-Protocol

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

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