So I am trying to orient a gameObject ( house in the picture below) which is nothing but a plane and has a 2d texture on it as you see below. The whole game is made on a hex sphere. I am using Orthographic camera projection for this game. I have oriented the house plane to the normal of the tile and rotated it by 90 degrees in x axis to begin with
cityDummy.transform.rotation = Quaternion.LookRotation(normal);
cityDummy.transform.Rotate(90, 0, 0);
Now I am trying to orient the house to make it look at the center ( blue capsule object in the image is the center point ) but I don't want to rotate it in all angles. Basically that is what LookRotation or LookAt does inside Unity. So after orienting the house with the normal, how do I make the house object look at the center and just rotate it in one axis that would be the y-axis in this case?
The reason why I need to do this is first of all I want to orient the house texture to the normal of the tile it gets placed on as you see in the image above. That works fine.
Now the next thing is we want them to face the south which is the blue capsule in the image above. So they would still be oriented like in the image below but the forward of the city should be facing south or towards the blue capsule. If I do LookAt it messes up the current orientation as it rotates in all axis. I would only want to rotate it on one axis and make it face the capsule
Answer
Quaternion.LookRotation(forward, up)
has a nifty property:
- it rotates z+ exactly to
forward
- it rotates y+ as close as possible to
up
(given the constraint on z+)
(You might not be used to up
, since it silently defaults to (0, 1, 0) if you leave this parameter out)
What we want here (and this comes up pretty often) is the reverse: we want y+ controlled exactly, and we want z+ to get as close as possible given this constraint.
We can get this just by playing with the axes a bit:
Vector3 lookDirection = target.transform.position - cityDummy.transform.position;
Quaternion rotation = Quaternion.LookRotation(normal, -lookDirection)
* Quaternion.AngleAxis(90f, Vector3.right);
This looks weird, so let me unpack it a bit...
We're using Quaternion.LookRotation with normal
in the first position (ordinarily used for forward
), to ensure the resulting rotation sticks to normal
exactly, and then aligns as close as possible to (negative) lookDirection
.
This gives us a rotation where the local z+ is pointing in the normal
direction, and local y- is pointing toward lookDirection
.
(If you orient your head this way, you're looking out of the sphere along the normal, and your chin is pointing toward the target)
But we want the axes switched. So we compose this with a rotation that takes y+ to z+, and z+ to y-, namely Quaternion.AngleAxis(90f, Vector3.right)
(Continuing with the head analogy, this corresponds to tilting your head forward 90 degrees)
The result of composing these two rotations with *
is a rotation that takes +y exactly to normal
, and +z as close as possible to lookDirection
.
I use this pattern so much, it might be worth adding it as an extension method to Quaternion, so you can get it with a single call, like Quaternion.LookRotationExactUp(forward, up)
No comments:
Post a Comment