I'm trying to implement an arcball type camera, I've got all controls working very nicely. I can rotate the X/Y axis with my mouse and zoom in and out with the Z/X keys.
The problem is, that the camera doesn't rotate around the model, but instead, the model rotates around its axis and the camera remains on the same position. When I zoom in or out, the model scales bigger or smaller. I've got the feeling my approach is incomplete or isn't correct..
In summary I want to achieve: rotate camera and zoom in/out on my model and still keep control of my model. How should I go about this?
This the code I'm using. Help or advice is much appreciated
Draw character
void DrawCharacter(Matrix view, Matrix projection)
{
// Render the skinned mesh.
Matrix[] bones = animationPlayer.GetSkinTransforms();
foreach (ModelMesh mesh in currentModel.Meshes)
{
foreach (SkinnedEffect effect in mesh.Effects)
{
effect.SetBoneTransforms(bones);
effect.View = view;
effect.Projection = projection;
effect.EnableDefaultLighting();
effect.SpecularColor = new Vector3(0.25f);
effect.SpecularPower = 16;
}
mesh.Draw();
}
}
Update camera
private void UpdateCamera(GameTime gameTime)
{
// start arcball
float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
// mouse movement
MouseState currentMouseState = Mouse.GetState();
if (currentMouseState != originalMouseState)
{
float xDifference = (currentMouseState.X - originalMouseState.X);
float yDifference = currentMouseState.Y - originalMouseState.Y;
Mouse.SetPosition(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2);
if (Mouse.GetState().RightButton == ButtonState.Pressed)
{
cameraRotation -= xDifference * 1.05f;
cameraArc += yDifference * 1.025f;
// Limit the arc movement.
if (cameraArc > 90.0f)
cameraArc = 90.0f;
else if (cameraArc < -90.0f)
cameraArc = -90.0f;
}
}
// Check for input to zoom camera in and out.
if (currentKeyboardState.IsKeyDown(Keys.Z))
cameraDistance += time * 0.25f;
if (currentKeyboardState.IsKeyDown(Keys.X))
cameraDistance -= time * 0.25f;
// Limit the camera distance.
if (cameraDistance > 500)
cameraDistance = 500;
else if (cameraDistance < 0.001f)
cameraDistance = 0.001f;
// reset camera
if (currentKeyboardState.IsKeyDown(Keys.R))
{
cameraArc = -5;
cameraRotation = 180;
cameraDistance = 100;
}
/// end of arcball
Matrix cameraFacingMatrix = Matrix.CreateRotationY(sphereFacingDirection);
Vector3 positionOffset = Vector3.Transform(CameraPositionOffset,
cameraFacingMatrix);
Vector3 targetOffset = Vector3.Transform(CameraTargetOffset,
cameraFacingMatrix);
Vector3 cameraPosition = spherePosition + positionOffset;
if (heightMapInfo.IsOnHeightmap(cameraPosition))
{
float minimumHeight = heightMapInfo.GetHeight(cameraPosition) + CameraPositionOffset.Y;
if (cameraPosition.Y < minimumHeight)
{
cameraPosition.Y = minimumHeight;
}
}
Vector3 cameraTarget = spherePosition + targetOffset;
// with those values, we'll calculate the viewMatrix.
viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraTarget, Vector3.Up);
}
Draw
protected override void Draw(GameTime gameTime)
{
GraphicsDevice device = graphics.GraphicsDevice;
device.Clear(Color.Gray);
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
// draw models
DrawModel(terrain, Matrix.Identity);
// Compute camera matrices.
float aspectRatio = (float)device.Viewport.Width / (float)device.Viewport.Height;
Matrix view = Matrix.CreateRotationY(MathHelper.ToRadians(cameraRotation)) *
Matrix.CreateRotationX(MathHelper.ToRadians(cameraArc)) *
Matrix.CreateTranslation(0, -45, 0) *
Matrix.CreateLookAt(new Vector3(0, forwardRotation, -cameraDistance),
new Vector3(0, 0, 0), Vector3.Up);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
aspectRatio,
1, 10000);
DrawCharacter(view, projection);
DrawAxe(view, projection);
base.Draw(gameTime);
}