Simplify my camera movement, sin cosine?

Started by
2 comments, last by groby 13 years, 9 months ago
Hey guys, after many hours using a pen and paper drawing circles and looking at coordinates, I managed to come up with a way to move my camera around the 0,0,0 point. What I was shooting for is the ability to move my camera all the way around a point (like the middle point of a sphere). It works as of right now just fine, but I am sure with some more advanced math I could scale this down. I am sure I am over-complicating it.

My comments for this post are in ***'s

The main gist of this is:
*** if Z is less than 0 and X is greater than 0, and I am moving left, I add a percentage of 1 to X and a percentage of 1 to Z. So if my X is 90 and my Z is 90, then I add a little to Z and a little to X, where as if my X is 1 and my Z is 179, I add a lot to one and a little to the other. This simulates smooth movement in an arc, depending on which quadrant I'm in.

The closer I get to an axis, the more I am adding to the X movement and less to the Z. This depends on which quadrant I'm in and it works the same for all quadrants.

Then I take the position and normalize it, then set it 180 units away from 0,0,0. The camera is always 180 units away from the center point 0,0,0.

It gets kind of stuttery when nearing a very high Z or a very high negative Z

The only thing I am changing is the camera position. The lookat is always the same, as well as the Up vector.

The video is kind of old but it is an old project I have just dusted off and was playing with.

http://www.youtube.com/user/Zuluplumber

protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

KeyboardState kb = Keyboard.GetState();

float thediff = (Math.Abs(campox.Z) / 180);
float thediff2 = 1.0f - ((Math.Abs(campox.Z) / 180));

//Console.WriteLine("thediff: " + thediff.ToString());
//Console.WriteLine("thediff2: " + thediff2.ToString());

if (kb.IsKeyDown(Keys.Down))
{
*** push down, the camera goes down the Y axis
campox.Y = campox.Y - unitspeed;
}
if (kb.IsKeyDown(Keys.Up))
{
*** push up, the camera goes up the Y axis
campox.Y = campox.Y + unitspeed;
}
if (kb.IsKeyDown(Keys.Left))
{
*** I divided the Z axis into 4 parts, and depending on which quadrant the camera is in, I add or subtract from my Z and X
if (campox.Z < 0 && campox.X >= 0)
{
*** if Z is less than 0 and X is greater than 0, and I am moving left, I add a percentage of 1 to X and a percentage of 1 to Z. So if my X is 90 and my Z is 90, then I add a little to Z and a little to X, where as if my X is 1 and my Z is 179, I add a lot to one and a little to the other. This simulates smooth movement in an arc, depending on which quadrant I'm in.
campox.X = campox.X + (thediff * unitspeed);
campox.Z = campox.Z + (thediff2 * unitspeed);
}
if (campox.X < 0 && campox.Z <= 0)
{
campox.X = campox.X + (thediff * unitspeed);
campox.Z = campox.Z - (thediff2 * unitspeed);
}
if (campox.Z > 0 && campox.X <= 0)
{
campox.X = campox.X - (thediff * unitspeed);
campox.Z = campox.Z - (thediff2 * unitspeed);
}
if (campox.X > 0 && campox.Z >= 0)
{
campox.X = campox.X - (thediff * unitspeed);
campox.Z = campox.Z + (thediff2 * unitspeed);
}
}
if (kb.IsKeyDown(Keys.Right))
{
if (campox.Z < 0 && campox.X >= 0)
{
campox.X = campox.X - (thediff * unitspeed);
campox.Z = campox.Z - (thediff2 * unitspeed);
}
if (campox.X < 0 && campox.Z <= 0)
{
campox.X = campox.X - (thediff * unitspeed);
campox.Z = campox.Z + (thediff2 * unitspeed);
}
if (campox.Z > 0 && campox.X <= 0)
{
campox.X = campox.X + (thediff * unitspeed);
campox.Z = campox.Z + (thediff2 * unitspeed);
}
if (campox.X > 0 && campox.Z >= 0)
{
campox.X = campox.X + (thediff * unitspeed);
campox.Z = campox.Z - (thediff2 * unitspeed);
}
}
base.Update(gameTime);
}

/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

worldMatrix =
Matrix.CreateRotationY(4.0f)*
Matrix.CreateRotationZ(-0.4f) *
Matrix.CreateScale(39.0f);

float tempcamy = campox.Y;
campox.Normalize();
campox = campox * 180.0f;
if (tempcamy < -160)
{
tempcamy = -160;
}
else if (tempcamy > 160)
{
tempcamy = 160;
}
campox.Y = tempcamy;

viewMatrix = Matrix.CreateLookAt(campox, new Vector3(0.0f, 0.0f, 0.0f), Vector3.Up);

base.Draw(gameTime);
}
Advertisement
Looks like a piecewise (exponential?) approximation to trig functions. I've played with things like that before, but there isn't really much point reinventing something for constant regular rotations since you only have to do the trig once, put it in a matrix, and then it's multiplications and additions each frame. Try looking up rotation matrices. If you're interested in more general (not just a circle) smooth movement then you'll probably want to look into cubic splines, bezier splines, and hermite splines as well.
That's the thing... I never took trig. I did what I have here with a pen and paper and my brain. Was just wondering if anyone could show me an easier way to do it. It works fine as it is now, but I'm sure it could be cleaned up by using sin or cosine or matrix functions.

I've gotten some help on another forum I had posted on, but have yet to try it out. I was able to get it working with some Matrix transformations too.

Thank you for the response though. After doing some major research on matrices this past weekend, I think I have it down what they are supposed to do.

I currenly have my viewmatrix as

CreateTranslation(0,rotation.Y,180) to move my camera 180 units from my 0,0,0.

Then I multiply that by Matrix.CreateRotationY so that I can "orbit" all the way around the 0,0,0 point. In my create translation I am able to change the Y value up, but since it goes straight up, if I keep it that way, it doesn't follow the smooth curve like I want it to.

So, what I did is every update, I normalize my vector3 camera position, then multiply it by 180 to always keep my camera 180 units from the 0,0,0. The only side effect of this is that as I near the top of my sphere, it goes slower and slower, because I am still increasing the Y value, but then normalizing it. The further I move up toward the top of the sphere, the less it moves forward (toward the Y axis). If I use createrotationx then my camera follows a true orbit where on one side of the sphere I am at +30 Y, then on the direct opposite side I am at -30 Y. The movement I am trying for is if I move "up" on the Y axis, I want to stay at that height no matter where I move to around the sphere. I'm sure I will figure it out playing with it AND I had someone help me on another forum. I just have to get time to try it out.
What you (more or less) did is derive a numerical approximation of trig. It sort-of works, but trig would make it much easier. You might want to look into it...


Anyways, if I understand you correctly, you want to rotate the camera around a point, constantly facing the point, right? Which means the camera is moving on a circle, with a fixed lookat.

There are two ways to go about this:

1) Take a point on the sphere, and rotate that point around the center. That gives you the camera position.

Which leaves the up-vector. Now, if you do some drawing, you'll see that there is your lookat vector, and the axis you rotate around. The up-vector will always be perpendicular to both - so you can get that by doing the cross-product of the rotation axis and the lookat.

2) If you think about it as the camera sees it, (i.e. in camera coordinate space) the world is rotating around the camera, in the opposite direction of where the camera is rotating.

So what you can do is create your camera view matrix, as if there was no rotation, and then concatenate it with a rotation around your axis with the negative of your rotation angle.

Either one should do the trick - if I understood you correctly.

This topic is closed to new replies.

Advertisement