Well i forgot all about this, I wrote this after a post between me and kwyky about the createlookat function. I meant to post it and forgot about it. This is like a 3d space sim camera. i could of fixed the y axis or done it a bit more but i never got around to it still its good for what it is a simple camera.
The idea was.
You add a world space object to a class.
You can then control it using the Input class.
Send it to the view space camera transformer.
You get back a combined worldviewprojection matrix.
Then you can send that to your shader.
It comprises of a WorldObjectSpace class made so that you can add a instance of this to your objects to move them around.
A ViewSpaceCameraTransform this is meant to turn any object that has a WorldObjectSpace instance in it into a camera. E.g. you can switch between objects as if they are the camera itself.
There is also a User Input controller class, its not that hot but its there just to move around the camera objects. It’s a work in progress
So here’s my World object camera class.
Edit:
This is the original as i have worked on it i have made and posted amendments.
I have left them in place so you can see the progression as it continued
I add things as i have need of them
Hopefully this will serve as a basic reference for creating a camera.
Edit2 The mouse look won’t work till the third update.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace CameraOperations
{
/// <summary>
/// Haven't set up a camera ? Don't feel like setting up stuff to move or rotate it
/// Lazy like me ? Maybe this will help.
/// Any world object could be a Camera.
/// </summary>
public class WorldSpaceObject
{
public Matrix world = Matrix.Identity;
public Vector3 Position
{
get { return world.Translation; }
set { world.Translation = value; }
}
public Vector3 Forward
{
get { return world.Forward; }
set { world = Matrix.CreateWorld(world.Translation, value, world.Up); }
}
/// <summary>
/// Move on a dimensional vector axis of the object itself. Note, we dont use the system vectors for this.
/// </summary>
public void Move(Vector3 moveSpeedInEachAxis)
{
var motion =
moveSpeedInEachAxis.X * world.Right +
moveSpeedInEachAxis.Y * world.Up +
moveSpeedInEachAxis.Z * world.Forward
;
Position += motion;
}
/// <summary>
/// We designate the dimensional speed of rotation in dimension x y or z upon a perpendicular axis.
/// We may change the cc or ccw of rotation by using the reverse inverted axis vector. or just negating
/// </summary>
public void Rotate(Vector3 turnSpeedInDimension)
{
Vector3 temp = world.Translation;
world *=
Matrix.CreateFromAxisAngle(world.Forward, turnSpeedInDimension.Z) *
Matrix.CreateFromAxisAngle(world.Up, turnSpeedInDimension.X) *
Matrix.CreateFromAxisAngle(world.Right, turnSpeedInDimension.Y)
;
Forward = world.Forward;
world.Translation = temp;
}
}
/// <summary>
/// This class takes a world space object to create a view camera. Via CreateCameraViewSpace.
/// You then get a combined world view projection matrix from GetWorldViewProjection.
/// </summary>
public class ViewSpaceCameraTransformer
{
public Vector3 OffsetPosition { get; set; }
public Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDeviceManager.DefaultBackBufferWidth / GraphicsDeviceManager.DefaultBackBufferHeight, .5f, 1000);
private Matrix viewSpace = Matrix.Identity;
/// <summary>
/// creates a camera view space matrixs and stores it
/// </summary>
public void CreateCameraViewSpace(WorldSpaceObject worldObjectToUseAsCamera)
{
viewSpace = Matrix.CreateLookAt
(
worldObjectToUseAsCamera.Position + OffsetPosition,
worldObjectToUseAsCamera.Forward + (worldObjectToUseAsCamera.Position + OffsetPosition),
worldObjectToUseAsCamera.world.Up
);
}
/// <summary>
/// Takes a world space object matrix and transforms it by view and projection space matrixs into screen space
/// </summary>
public Matrix GetWorldViewProjection(WorldSpaceObject worldObject)
{
return worldObject.world * viewSpace * projection;
}
}
/// <summary>
/// Use keys mouse or what not To move WorldSpaceObjects Around.
/// This could probably be better.
/// </summary>
public class UserInputToOrientWorldObject
{
Vector3 turnOnAxis = Vector3.Zero;
Vector3 moveInAxis = Vector3.Zero;
float SpeedMovement = .01f;
float SpeedRotational = .01f;
bool didAnyChangeOccur = false;
public bool HasChangeOccured { get { return didAnyChangeOccur; } }
Vector2 windowcenter = new Vector2(GraphicsDeviceManager.DefaultBackBufferWidth * .5f, GraphicsDeviceManager.DefaultBackBufferHeight * .5f);
public Keys KeyMoveRight = Keys.D;
public Keys KeyMoveLeft = Keys.A;
public Keys KeyMoveUp = Keys.W;
public Keys KeyMoveDown = Keys.S;
public Keys KeyMoveForward = Keys.E;
public Keys KeyMoveBack = Keys.Q;
public Keys KeyLookRight = Keys.Right;
public Keys KeyLookLeft = Keys.Left;
public Keys KeyLookUp = Keys.Up;
public Keys KeyLookDown = Keys.Down;
public Keys KeySpinCW = Keys.Z;
public Keys KeySpinCCW = Keys.C;
private bool useMouseLook = false;
// if this is never called will just use the default key assignments
public bool UseMouseLook
{
get { return useMouseLook; }
set
{
if (value)
{
KeyMoveForward = Keys.W;
KeyMoveBack = Keys.S;
// just move them out of the way
KeyMoveUp = Keys.Home;
KeyMoveDown = Keys.PageUp;
}
else
{
KeyMoveRight = Keys.D;
KeyMoveLeft = Keys.A;
KeyMoveUp = Keys.W;
KeyMoveDown = Keys.S;
KeyMoveForward = Keys.E;
KeyMoveBack = Keys.Q;
}
useMouseLook = value;
}
}
public void SetWindowSizeRequiredForMouseLook(GraphicsDevice g)
{
windowcenter = new Vector2(g.Viewport.Width * .5f, g.Viewport.Height * .5f);
}
public void SetWindowSizeRequiredForMouseLook(int width, int height)
{
windowcenter = new Vector2(width * .5f, height * .5f);
}
public WorldSpaceObject UpdateOrientation(WorldSpaceObject worldObj)
{
didAnyChangeOccur = false;
if (useMouseLook)
{
MouseLook();
Move();
}
else
{
Rotate();
Move();
}
if (didAnyChangeOccur)
{
worldObj.Move(moveInAxis);
worldObj.Rotate(turnOnAxis);
}
return worldObj;
}
private void Rotate()
{
turnOnAxis = Vector3.Zero;
if (Keyboard.GetState().IsKeyDown(KeySpinCCW)) // roll ccw
{
turnOnAxis.Z = -SpeedRotational;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeySpinCW)) // roll cw
{
turnOnAxis.Z = SpeedRotational;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyLookLeft)) // r ccw
{
turnOnAxis.X = SpeedRotational;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyLookRight)) // r cw
{
turnOnAxis.X = -SpeedRotational;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyLookUp)) // u cw
{
turnOnAxis.Y = SpeedRotational;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyLookDown)) // d ccw
{
turnOnAxis.Y = -SpeedRotational;
didAnyChangeOccur = true;
}
}
private void Move()
{
moveInAxis = Vector3.Zero;
if (Keyboard.GetState().IsKeyDown(KeyMoveForward)) // Forward
{
moveInAxis.Z = SpeedMovement;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyMoveBack)) // back
{
moveInAxis.Z = -SpeedMovement;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyMoveLeft)) // left
{
moveInAxis.X = -SpeedMovement;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyMoveRight)) // right
{
moveInAxis.X = SpeedMovement;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyMoveDown)) // down
{
moveInAxis.Y = -SpeedMovement;
didAnyChangeOccur = true;
}
if (Keyboard.GetState().IsKeyDown(KeyMoveUp)) // up
{
moveInAxis.Y = SpeedMovement;
didAnyChangeOccur = true;
}
}
private void MouseLook()
{
turnOnAxis = Vector3.Zero;
Vector2 mousePos = new Vector2(Mouse.GetState().Position.X, Mouse.GetState().Position.Y) - windowcenter;
Vector2 mouseAngle = Vector2.Normalize(mousePos);
if (Mouse.GetState().LeftButton == ButtonState.Pressed)
{
Matrix r = Matrix.Identity;
mousePos.Normalize();
if (mousePos.Y > 5f)
{
turnOnAxis.Y = SpeedRotational * mouseAngle.Y;
didAnyChangeOccur = true;
}
if (mousePos.Y < 5f)
{
turnOnAxis.Y = SpeedRotational * mouseAngle.Y;
didAnyChangeOccur = true;
}
if (mousePos.X > 5f)
{
turnOnAxis.X = SpeedRotational * mouseAngle.X;
didAnyChangeOccur = true;
}
if (mousePos.X < 5f)
{
turnOnAxis.X = SpeedRotational * mouseAngle.X;
didAnyChangeOccur = true;
}
}
}
}
}
It’s not tested a lot but
It seems to work pretty well from as much as i did test it.
I don’t think i ever tested the mouse look input at all though…
using it in update looks something like this.
// were cam and someobject are or contain a WorldspaceObject
cam = uiInput.UpdateOrientation(cam);
if (uiInput.HasChangeOccured)
{
transformer.CreateCameraViewSpace(cam);
}
// this might end up in draw.
worldviewprojection = transformer.GetWorldViewProjection(cam);
// or
worldviewprojection = transformer.GetWorldViewProjection(someobj_B);
.
Edit:
The following amendments have been since made to the above set of classes.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
// Replace the below namespace with your own projects namespace
namespace CameraOperations
{
/// <summary>
/// Haven't set up a camera ?
/// Don't feel like setting up stuff to move or rotate
/// Add one of these objects to your class.
/// </summary>
public class WorldSpaceObject
{
public Matrix world = Matrix.Identity;
/// <summary>
/// While the rotations are in fact axis angle rotations.
/// About the current objects orientation, we still have a multiplication order.
/// </summary>
public bool UseYawPitchRollToRotate
{
get;
set;
}
public Vector3 Position
{
get { return world.Translation; }
set { world.Translation = value; }
}
public Vector3 Forward
{
get { return world.Forward; }
set { world = Matrix.CreateWorld(world.Translation, value, world.Up); }
}
/// <summary>
/// Move on a dimensional vector axis of the object itself. Note, we dont use the system vectors for this.
/// </summary>
public void Move(Vector3 moveSpeedInEachAxis)
{
var motion =
moveSpeedInEachAxis.X * world.Right +
moveSpeedInEachAxis.Y * world.Up +
moveSpeedInEachAxis.Z * world.Forward
;
Position += motion;
}
/// <summary>
/// We designate the dimensional speed of rotation in dimension x y or z upon a perpendicular axis.
/// We may change the cw or ccw of rotation by using the reverse inverted axis vector. or just negating
/// </summary>
public void Rotate(Vector3 turnSpeedInDimension)
{
Vector3 temp = world.Translation;
if (UseYawPitchRollToRotate)
{
world *=
Matrix.CreateFromAxisAngle(world.Right, turnSpeedInDimension.Y) *
Matrix.CreateFromAxisAngle(world.Up, turnSpeedInDimension.X) *
Matrix.CreateFromAxisAngle(world.Forward, turnSpeedInDimension.Z)
;
Forward = world.Forward;
}
else
{
world *=
Matrix.CreateFromAxisAngle(world.Forward, turnSpeedInDimension.Z) *
Matrix.CreateFromAxisAngle(world.Up, turnSpeedInDimension.X) *
Matrix.CreateFromAxisAngle(world.Right, turnSpeedInDimension.Y)
;
Forward = world.Forward;
}
world.Translation = temp;
}
}
/// <summary>
/// This class takes a world space object to create a view camera. Via CreateCameraViewSpace.
/// You then get a combined world view projection matrix from GetWorldViewProjection.
/// </summary>
public class ViewSpaceCameraTransformer
{
private Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, GraphicsDeviceManager.DefaultBackBufferWidth / GraphicsDeviceManager.DefaultBackBufferHeight, .5f, 1000);
private Matrix viewSpace = Matrix.Identity;
private Matrix combinedViewProjection;
/// <summary>
/// This can be used as a camera offset such as for a chase view.
/// </summary>
public Vector3 OffsetPosition
{
get;
set;
}
/// <summary>
/// Get a default projection matrix or set a new one
/// </summary>
public Matrix Projection
{
get
{
return projection;
}
set
{
projection = value;
combinedViewProjection = viewSpace * projection;
}
}
/// <summary>
/// creates a camera view space, matrice and stores it.
/// </summary>
public void CreateCameraViewSpace(WorldSpaceObject worldObjectToUseAsCamera)
{
viewSpace = Matrix.CreateLookAt
(
worldObjectToUseAsCamera.Position + OffsetPosition,
worldObjectToUseAsCamera.Forward + (worldObjectToUseAsCamera.Position + OffsetPosition),
worldObjectToUseAsCamera.world.Up
);
combinedViewProjection = viewSpace * projection;
}
/// <summary>
/// Takes a world space object matrice and transforms it.
/// By the view and projection matrixs into screen space.
/// </summary>
public Matrix GetWorldViewProjection(WorldSpaceObject worldObject)
{
return worldObject.world * combinedViewProjection;
}
}
/// <summary>
/// Use keys mouse or what not To move WorldSpaceObjects Around.
/// This could probably be better.
/// </summary>
public class UserInputToOrientWorldObject
{
Vector3 turnOnAxis = Vector3.Zero;
Vector3 moveInAxis = Vector3.Zero;
float SpeedMovement = .01f;
float SpeedRotational = .01f;
bool didAnyChangeOccur = false;
public bool HasChangeOccured { get { return didAnyChangeOccur; } }
Vector2 windowcenter = new Vector2(GraphicsDeviceManager.DefaultBackBufferWidth * .5f, GraphicsDeviceManager.DefaultBackBufferHeight * .5f);
KeyboardState keyStates;
MouseState mouseStates;
public Keys KeyMoveRight = Keys.D;
public Keys KeyMoveLeft = Keys.A;
public Keys KeyMoveUp = Keys.W;
public Keys KeyMoveDown = Keys.S;
public Keys KeyMoveForward = Keys.E;
public Keys KeyMoveBack = Keys.Q;
public Keys KeyLookRight = Keys.Right;
public Keys KeyLookLeft = Keys.Left;
public Keys KeyLookUp = Keys.Up;
public Keys KeyLookDown = Keys.Down;
public Keys KeySpinCW = Keys.Z;
public Keys KeySpinCCW = Keys.C;
private bool useMouseLook = false;
// if this is never called will just use the default key assignments
public bool UseMouseLook
{
get { return useMouseLook; }
set
{
if (value)
{
KeyMoveForward = Keys.W;
KeyMoveBack = Keys.S;
// just move them out of the way
KeyMoveUp = Keys.Home;
KeyMoveDown = Keys.PageUp;
}
else
{
KeyMoveRight = Keys.D;
KeyMoveLeft = Keys.A;
KeyMoveUp = Keys.W;
KeyMoveDown = Keys.S;
KeyMoveForward = Keys.E;
KeyMoveBack = Keys.Q;
}
useMouseLook = value;
}
}
public void SetWindowSizeRequiredForMouseLook(GraphicsDevice g)
{
windowcenter = new Vector2(g.Viewport.Width * .5f, g.Viewport.Height * .5f);
}
public void SetWindowSizeRequiredForMouseLook(int width, int height)
{
windowcenter = new Vector2(width * .5f, height * .5f);
}
public WorldSpaceObject UpdateOrientation(WorldSpaceObject worldObj)
{
didAnyChangeOccur = false;
keyStates = Keyboard.GetState();
mouseStates = Mouse.GetState();
if (useMouseLook)
{
MouseLook();
Move();
}
else
{
Rotate();
Move();
}
if (didAnyChangeOccur)
{
worldObj.Move(moveInAxis);
worldObj.Rotate(turnOnAxis);
}
return worldObj;
}
private void Rotate()
{
turnOnAxis = Vector3.Zero;
if (keyStates.IsKeyDown(KeySpinCCW)) // roll ccw
{
turnOnAxis.Z = -SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeySpinCW)) // roll cw
{
turnOnAxis.Z = SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookLeft)) // r ccw
{
turnOnAxis.X = SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookRight)) // r cw
{
turnOnAxis.X = -SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookUp)) // u cw
{
turnOnAxis.Y = SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookDown)) // d ccw
{
turnOnAxis.Y = -SpeedRotational;
didAnyChangeOccur = true;
}
}
private void Move()
{
moveInAxis = Vector3.Zero;
if (keyStates.IsKeyDown(KeyMoveForward)) // Forward
{
moveInAxis.Z = SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveBack)) // back
{
moveInAxis.Z = -SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveLeft)) // left
{
moveInAxis.X = -SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveRight)) // right
{
moveInAxis.X = SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveDown)) // down
{
moveInAxis.Y = -SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveUp)) // up
{
moveInAxis.Y = SpeedMovement;
didAnyChangeOccur = true;
}
}
private void MouseLook()
{
turnOnAxis = Vector3.Zero;
Vector2 mousePos = new Vector2(mouseStates.Position.X, mouseStates.Position.Y) - windowcenter;
Vector2 mouseAngle = Vector2.Normalize(mousePos);
//if (mouseStates.LeftButton == ButtonState.Pressed)
//{
Matrix r = Matrix.Identity;
mousePos.Normalize();
if (mousePos.Y > 5f)
{
turnOnAxis.Y = SpeedRotational * mouseAngle.Y;
didAnyChangeOccur = true;
}
if (mousePos.Y < 5f)
{
turnOnAxis.Y = SpeedRotational * mouseAngle.Y;
didAnyChangeOccur = true;
}
if (mousePos.X > 5f)
{
turnOnAxis.X = SpeedRotational * mouseAngle.X;
didAnyChangeOccur = true;
}
if (mousePos.X < 5f)
{
turnOnAxis.X = SpeedRotational * mouseAngle.X;
didAnyChangeOccur = true;
}
//}
}
}
}