views:

155

answers:

1

Hello,

Im doing some practices on XNA, and i created a class that represents a Camera.

My objective is that when the user press some keys make a translation of the camera (not the target) 90 degrees in the X axys (to see an object that i placed in the scene from different angles). By the moment i move the camera in X, Y, and Z without problems.

Actually to set up my camera i use the following lines of code:

public void SetUpCamera()
{
            #region ## SET DEFAULTS ##
            this.FieldOfViewAngle = 45.0f;
            this.AspectRatio =1f;
            this.NearPlane = 1.0f;
            this.FarPlane = 10000.0f;
            #endregion

            this.ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(this.FieldOfViewAngle), 16 / 9, this.NearPlane, this.FarPlane);
            this.ViewMatrix = Matrix.CreateLookAt(new Vector3(this.PositionX, this.PositionY, this.PositionZ), new Vector3(this.TargetX, this.TargetY, this.TargetZ), Vector3.Up);
}

I have this method to move the camera:

public void UpdateView()
{
     this.ViewMatrix = Matrix.CreateLookAt(new Vector3(this.PositionX, this.PositionY, this.PositionZ), new Vector3(this.TargetX, this.TargetY, this.TargetZ), Vector3.Up);
}

Then in the game (update event handler i have the following code)

if (keyboardstate.IsKeyDown(Keys.NumPad9))
{
   this.GameCamera.PositionZ -= 1.0f;
}
if (keyboardstate.IsKeyDown(Keys.NumPad3))
{
   this.GameCamera.PositionZ += 1.0f;
}
this.GameCamera.UpdateView();

I would like to know how to make this camera translation of 90 degrees to surround one object that i placed in the screen.

To explain my self better about the camera movement here is a video on youtube that uses the exact movement that im trying to describe (see from 14 second) http://www.youtube.com/watch?v=19mbKZ0I5u4

Thanks for your help in advance.

Best Regards.

Jose

+1  A: 

Assuming the camera in the video is orbiting the car, here is how you would accomplish that in XNA.

For the sake of readability, we'll just use vectors instead of their individual components. So 'target' means it's a Vector3 that includes TargetX, TargetY, & TargetZ. Same with the camera’s position. You can break X, Y, Z values out into fields and make Vector3s out of them to plug into this code if you want to later, but really it would be best for you to work at vector level instead of component level.

//To orbit the car (target)
cameraPosition = Vector3.Transform(cameraPosition – target, Matrix.CreateRotationY(0.01f)) + target;
this.ViewMatrix = Matrix.CreateLookAt(cameraPosition, target, Vector3.Up);

Since all matrix rotations act about an axis that intersects the world origin, to use a rotation matrix to rotate the camera around the car, the object of rotation has to be shifted such that the target (and thus the rotation axis) is located at the world origin. CameraPosition - target accomplishes that. Now cameraPosition can be rotated a little bit. Once cameraPosition is rotated a little bit, it needs to be sent back to the scene at hand, that's what the '+ target' at the end of the line is for.

The 0.01f can be adjusted to whatever rotation rate suits you.

Steve H
There are a few minor flaws in this solution: 1) The rotation rate should be multiplied by the elapsed time that frame. 2) I would suggest accumulating the rotation in the angle, rather than the camera position itself - and for good measure I'd probably use `WrapAngle` on the angle.
Andrew Russell
@Andrew. 1) I agree in practice but I left 'elapsed time' out purposefully to simplify the algorithm so it could be visualized and understood better. Perhaps not a good choice, I don't know.2) I disagree on this one. It is not good, in 3d, to store angles that have to do with rotations/orientations from frame to frame. In 2d, storing an angular representation of something's orientation is good and proper. In 3d, it's bad. See this link, with an emphasis on the last paragraph on the blog post: http://blogs.msdn.com/b/shawnhar/archive/2010/02/12/doing-math-in-2d-vs-3d.aspx
Steve H
@Steve I am afraid I disagree. While you are quite right about not using angles for calculations as a general rule, it is perfectly valid to use an angle to place an orbit camera. You have to create a rotation matrix from an angle in order to trace out a circle (you do so yourself). I simply suggest a better way to store it. The thrust of Shawn's article is that an implementation of something like `CreateLookAt` should not use angles and trigonometry - but dot and cross products (which it does).
Andrew Russell
Your angle approach requires the rotation axis to be constant which, although in the OP's case it may be, is not always the case. In 3d, unlike 2d, the axis is not constrained. So if, say for effect, the orbit axis were altered in mid orbit, your angle approach suffers without additional math complexity. My approach doesn't. --- The bottom line isn't that you 'shouldn't use angles in general' it is that 'you shouldn't use angles to store orientation info' because an angle demands an axis and you are then constrained to that axis or to unnecessary math to resolve 3rd dimension changes.
Steve H
Not quite. A circular orbit camera consists of an origin (a translation), a plane of rotation (a rotation), an angle (a rotation), and a distance (a translation) - four transformation steps. All of which can be animated independently and should be stored as such. You could even store the two rotation steps as the dreaded "three angles". In the case of a circular orbit, gimbal lock is not such a problem. For a free-orbit camera, something more robust may be appropriate (but you can't accumulate quaternions either - see also stackoverflow.com/questions/319189).
Andrew Russell
Steve H
Steve H