- Home /
How do you combine local and planar translation?
I have a camera, tilted on its local x axis, to look upon the world below at an angle. I want to move it around based on some input. However, I'm not sure what the best way is, to move it the exact way I want.
- Movement needs to be in a plane parallel with the world's XZ plane.
- X input needs to map to local X translation.
- Y input needs to map to neither the local Z, nor a world axis. Instead, it needs to be along the vector that you get when you take transform.forward and rotate it along the local X axis to be parallel with the XZ plane.
Another way to do this would be to give the transform a parent. The parent would not be rotated in X. Movement along the parent's axes would be perfect. I just don't want the overhead and complexity of that.
My current idea is to take a vector that represents this "alternative local translation", and rotate it around the world's Y axis. I don't really like having to rely on Euler angles, but this seems to be working so far. Got a better solution? Is there some kind of general solution, and if so, would this or something else be faster, given the constraints?
transform.position += Quaternion.Euler(0, transform.eulerAngles.y, 0) * xyzVector;
Added some more to my answer below (in response to your comments).
Answer by Jesse Anders · Feb 20, 2011 at 10:44 AM
if you don't want to use parenting, then one way to compute the forward vector would be (assuming I'm understanding the question correctly):
var forward = transform.forward;
forward.y = 0f; // Adjust for programming language if needed
forward.Normalize();
This will give you the same result as rotating the forward vector about the local X axis so as to be parallel with the XZ plane, as you described. The only caveat is that it may fail if the camera is looking straight up or down or nearly straight up or down. If you know the X rotation will be within a 'safe' range though, this method should work.
Another method would be to actually counter-rotate the forward vector about the X axis, just as you described (although the normalization method described above is a little more straightforward, code-wise).
IMO, using parenting would probably be the cleanest and most straightforward solution, but the other methods under discussion should work as well.
[Edit: In response to comment below...]
If the concern is performance-related, I'd guess that all the methods under discussion would probably have a similar cost. (That's just a guess of course - you'd have to actually compare them to be sure.) So from that standpoint, I'd just go with whatever makes the most logical sense.
The only other option I can think of aside from what's already been discussed is to store the orientation of the object as a pair of angles (pitch and yaw), update those angles in response to user input, and then rebuild the orientation from scratch each update from those angles, e.g.:
transform.eulerAngles = new Vector3(pitch, yaw, 0f);
Using Euler angles in this way is perfectly suitable for this type of motion, and if you have the 'yaw' angle stored separately, you can then easily compute the 'XZ plane' movement vector as needed.
It sounds like your objection to the parenting method is mostly conceptual. If so, I'd argue that the parenting method actually makes perfect sense from both a functional and organizational standpoint. It's just like any other scenario where the orientation of one object is dependent on another; even the 'first-person controller' that ships with Unity (or shipped with previous versions, at least) makes use of parenting in exactly this way. This method can be used effectively any time one orientation needs to depend on and yet be independent from another (e.g. a 'banking' effect for a spacecraft, a 'bobbing' effect for a character, etc.).
In this case, you have two logically distinct behaviors; one object moves about in a plane that's parallel to the XZ plane, while another, related object follows the position and orientation of that object, but is free to rotate about the local x axis.
Anyway, that's the method I'd use. Failing that, I'd go with 'yaw' and 'pitch' angles. After that would come the other ideas that have been discussed, and after that I'm out of ideas :)
That's fine, but requires renormalizing. Sorry, I should have mentioned that I had already thought of that and specifically didn't want to do it, for that reason. I assume Quaternion.Euler is doing something just as bad or worse. I don't think parenting is a good option, because I then have a game object in the scene that creates a hierarchy that is only useful for transformation, not organization, and I aim for both, with a focus on the latter, even. Having to waste space in the Hierarchy for two game objects, for this, is...ObjecTionable.
Your answer
Follow this Question
Related Questions
Rotating on a plane 2 Answers
Limit local rotation 6 Answers
Rotating Object on its Local World Axis 4 Answers
World and Local Axis out of Alignment 1 Answer
Limit local Rotations on one axis 3 Answers