Camera class now abstract, split off into specific perspective cameras
This commit is contained in:
parent
e5a12a4cb1
commit
421ecc9f43
|
@ -135,7 +135,6 @@
|
|||
<Compile Include="Graphics\SpriteBatch.cs" />
|
||||
<Compile Include="Graphics\BillboardSpriteBatch.cs" />
|
||||
<Compile Include="Graphics\Helpers\FlatWireframeGrid.cs" />
|
||||
<Compile Include="Support\FreeMovementCamera.cs" />
|
||||
<Compile Include="Support\StringBuilderExtensions.cs" />
|
||||
<Compile Include="Graphics\Helpers\GraphicsHelpers.cs" />
|
||||
<Compile Include="Support\BitExtensions.cs" />
|
||||
|
@ -225,6 +224,8 @@
|
|||
<Compile Include="Entities\EntityPreset.cs" />
|
||||
<Compile Include="Entities\EntityPresetArgs.cs" />
|
||||
<Compile Include="Entities\SystemComponents\EntityPresetComponent.cs" />
|
||||
<Compile Include="Graphics\PerspectiveCamera.cs" />
|
||||
<Compile Include="Graphics\EulerPerspectiveCamera.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace Blarg.GameFramework.Graphics
|
|||
throw new InvalidOperationException();
|
||||
|
||||
_cameraPosition = GraphicsDevice.ViewContext.Camera.Position;
|
||||
_cameraForward = GraphicsDevice.ViewContext.Camera.Forward;
|
||||
_cameraForward = GraphicsDevice.ViewContext.Camera.Direction;
|
||||
|
||||
if (shader == null)
|
||||
_shader = GraphicsDevice.Sprite3DShader;
|
||||
|
|
|
@ -2,100 +2,58 @@ using System;
|
|||
|
||||
namespace Blarg.GameFramework.Graphics
|
||||
{
|
||||
public class Camera
|
||||
public abstract class Camera
|
||||
{
|
||||
ViewContext _viewContext;
|
||||
float _nearHeight;
|
||||
float _nearWidth;
|
||||
|
||||
public readonly Frustum Frustum;
|
||||
public Matrix4x4 LookAt;
|
||||
public Matrix4x4 Projection;
|
||||
public Vector3 Forward;
|
||||
public Vector3 Up;
|
||||
|
||||
public Vector3 Orientation;
|
||||
public Vector3 Position;
|
||||
public Vector3 Direction;
|
||||
public Vector3 Up;
|
||||
public float Near;
|
||||
public float Far;
|
||||
|
||||
public int ViewportWidth { get; private set; }
|
||||
public int ViewportHeight { get; private set; }
|
||||
public float AspectRatio { get; private set; }
|
||||
public float Near { get; private set; }
|
||||
public float Far { get; private set; }
|
||||
public float FieldOfViewAngle { get; private set; }
|
||||
public int ViewportWidth { get; protected set; }
|
||||
public int ViewportHeight { get; protected set; }
|
||||
|
||||
public Camera(ViewContext viewContext, float near = 1.0f, float far = 50.0f, float fieldOfView = MathConstants.Radians60)
|
||||
protected readonly ViewContext ViewContext;
|
||||
protected float NearWidth;
|
||||
protected float NearHeight;
|
||||
|
||||
public Camera(ViewContext viewContext, float near = 1.0f, float far = 50.0f)
|
||||
{
|
||||
if (viewContext == null)
|
||||
throw new ArgumentNullException("viewContext");
|
||||
|
||||
_viewContext = viewContext;
|
||||
ViewContext = viewContext;
|
||||
Frustum = new Frustum(this);
|
||||
Position = Vector3.Zero;
|
||||
Orientation = Vector3.Zero;
|
||||
Forward = Vector3.Zero;
|
||||
Direction = Vector3.Forward;
|
||||
Up = Vector3.Up;
|
||||
LookAt = Matrix4x4.Identity;
|
||||
|
||||
FieldOfViewAngle = fieldOfView;
|
||||
Near = near;
|
||||
Far = far;
|
||||
|
||||
CalculateDefaultProjection(
|
||||
_viewContext.ViewportLeft,
|
||||
_viewContext.ViewportTop,
|
||||
_viewContext.ViewportRight,
|
||||
_viewContext.ViewportBottom
|
||||
);
|
||||
Update();
|
||||
}
|
||||
|
||||
public virtual void OnUpdate(float delta)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnRender(float delta)
|
||||
{
|
||||
Vector3 movement = Vector3.Zero;
|
||||
UpdateLookAtMatrix(ref movement);
|
||||
_viewContext.ModelViewMatrix = LookAt;
|
||||
Frustum.Calculate();
|
||||
}
|
||||
|
||||
public virtual void OnResize(ref Rect size)
|
||||
{
|
||||
CalculateDefaultProjection(size.Left, size.Top, size.Right, size.Bottom);
|
||||
_viewContext.ProjectionMatrix = Projection;
|
||||
}
|
||||
|
||||
public virtual void UpdateProjectionMatrix()
|
||||
{
|
||||
CalculateDefaultProjection(
|
||||
_viewContext.ViewportLeft,
|
||||
_viewContext.ViewportTop,
|
||||
_viewContext.ViewportRight,
|
||||
_viewContext.ViewportBottom
|
||||
);
|
||||
}
|
||||
|
||||
public virtual void UpdateLookAtMatrix(ref Vector3 movement)
|
||||
{
|
||||
CalculateDefaultLookAt(ref movement);
|
||||
}
|
||||
public abstract void Update();
|
||||
|
||||
public Ray Pick(int screenX, int screenY)
|
||||
{
|
||||
float nx = 2.0f * ((float)(screenX - (_viewContext.ViewportWidth / 2))) / ((float)_viewContext.ViewportWidth);
|
||||
float ny = 2.0f * -((float)(screenY - (_viewContext.ViewportHeight / 2))) / ((float)_viewContext.ViewportHeight);
|
||||
float nx = 2.0f * ((float)(screenX - (ViewContext.ViewportWidth / 2))) / ((float)ViewContext.ViewportWidth);
|
||||
float ny = 2.0f * -((float)(screenY - (ViewContext.ViewportHeight / 2))) / ((float)ViewContext.ViewportHeight);
|
||||
|
||||
// pick ray calculation method copied from http://code.google.com/p/libgdx/
|
||||
Vector3 vz = Vector3.Normalize(Forward * -1.0f);
|
||||
Vector3 vz = Vector3.Normalize(Direction * -1.0f);
|
||||
Vector3 vx = Vector3.Normalize(Vector3.Cross(Vector3.Up, vz));
|
||||
Vector3 vy = Vector3.Normalize(Vector3.Cross(vz, vx));
|
||||
|
||||
Vector3 near_center = Position - (vz * Near);
|
||||
|
||||
Vector3 a = (vx * _nearWidth) * nx;
|
||||
Vector3 b = (vy * _nearHeight) * ny;
|
||||
Vector3 a = (vx * NearWidth) * nx;
|
||||
Vector3 b = (vy * NearHeight) * ny;
|
||||
Vector3 near_point = a + b + near_center;
|
||||
|
||||
Vector3 dir = Vector3.Normalize(near_point - Position);
|
||||
|
@ -105,8 +63,8 @@ namespace Blarg.GameFramework.Graphics
|
|||
|
||||
public Point2 Project(ref Vector3 objectPosition)
|
||||
{
|
||||
Matrix4x4 modelview = _viewContext.ModelViewMatrix;
|
||||
Matrix4x4 projection = _viewContext.ProjectionMatrix;
|
||||
Matrix4x4 modelview = ViewContext.ModelViewMatrix;
|
||||
Matrix4x4 projection = ViewContext.ProjectionMatrix;
|
||||
|
||||
return Project(ref objectPosition, ref modelview, ref projection);
|
||||
}
|
||||
|
@ -137,44 +95,14 @@ namespace Blarg.GameFramework.Graphics
|
|||
|
||||
// map to 2D viewport coordinates (ignoring Z)
|
||||
Point2 result;
|
||||
result.X = (int)(((transformedX * 0.5f) + 0.5f) * (float)_viewContext.PixelScaler.ScaledWidth + (float)_viewContext.PixelScaler.ScaledViewport.Left);
|
||||
result.Y = (int)(((transformedY * 0.5f) + 0.5f) * (float)_viewContext.PixelScaler.ScaledHeight + (float)_viewContext.PixelScaler.ScaledViewport.Top);
|
||||
result.X = (int)(((transformedX * 0.5f) + 0.5f) * (float)ViewContext.PixelScaler.ScaledWidth + (float)ViewContext.PixelScaler.ScaledViewport.Left);
|
||||
result.Y = (int)(((transformedY * 0.5f) + 0.5f) * (float)ViewContext.PixelScaler.ScaledHeight + (float)ViewContext.PixelScaler.ScaledViewport.Top);
|
||||
// float z = (1.0f + transformedZ) * 0.5f; // would be between 0.0f and 1.0f
|
||||
|
||||
// adjust Y coordinate so that 0 is at the top of the screen instead of the bottom
|
||||
result.Y = (int)_viewContext.PixelScaler.ScaledHeight - result.Y;
|
||||
result.Y = (int)ViewContext.PixelScaler.ScaledHeight - result.Y;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void CalculateDefaultProjection(int left, int top, int right, int bottom)
|
||||
{
|
||||
ViewportWidth = right - left;
|
||||
ViewportHeight = bottom - top;
|
||||
|
||||
AspectRatio = (float)ViewportWidth / (float)ViewportHeight;
|
||||
|
||||
_nearHeight = Near * (float)Math.Tan(FieldOfViewAngle / 2.0f);
|
||||
_nearWidth = _nearHeight * AspectRatio;
|
||||
|
||||
Projection = Matrix4x4.CreatePerspectiveFieldOfView(FieldOfViewAngle, AspectRatio, Near, Far);
|
||||
}
|
||||
|
||||
protected void CalculateDefaultLookAt(ref Vector3 movement)
|
||||
{
|
||||
// final camera orientation. angles must be negative (or rather, inverted) for the camera matrix. also the matrix concatenation order is important!
|
||||
Matrix4x4 rotation = Matrix4x4.CreateRotationY(-Orientation.Y) * Matrix4x4.CreateRotationX(-Orientation.X);
|
||||
|
||||
// apply orientation to forward, movement and up vectors so they're pointing in the right direction
|
||||
Forward = Matrix4x4.Transform(rotation, Vector3.Forward);
|
||||
Up = Matrix4x4.Transform(rotation, Vector3.Up);
|
||||
Vector3 orientedMovement = Matrix4x4.Transform(rotation, movement);
|
||||
|
||||
// move the camera position
|
||||
Position += orientedMovement;
|
||||
|
||||
Vector3 target = Forward + Position;
|
||||
LookAt = Matrix4x4.CreateLookAt(Position, target, Vector3.Up);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
37
Blarg.GameFramework/Graphics/EulerPerspectiveCamera.cs
Normal file
37
Blarg.GameFramework/Graphics/EulerPerspectiveCamera.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using Blarg.GameFramework.TileMap;
|
||||
|
||||
namespace Blarg.GameFramework.Graphics
|
||||
{
|
||||
public class EulerPerspectiveCamera : PerspectiveCamera
|
||||
{
|
||||
public float Yaw;
|
||||
public float Pitch;
|
||||
|
||||
public Quaternion Rotation;
|
||||
|
||||
public EulerPerspectiveCamera(ViewContext viewContext, float near = 1.0f, float far = 50.0f, float fieldOfView = MathConstants.Radians60)
|
||||
: base(viewContext, near, far, fieldOfView)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
UpdateRotation();
|
||||
|
||||
CalculateProjection();
|
||||
CalculateLookAt();
|
||||
}
|
||||
|
||||
public void UpdateRotation()
|
||||
{
|
||||
var rotationX = Quaternion.CreateFromAxisAngle(-Pitch, Vector3.XAxis);
|
||||
var rotationY = Quaternion.CreateFromAxisAngle(-Yaw, Vector3.YAxis);
|
||||
Rotation = rotationY * rotationX;
|
||||
|
||||
Direction = Quaternion.Transform(Rotation, Vector3.Forward);
|
||||
Up = Quaternion.Transform(Rotation, Vector3.Up);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
Blarg.GameFramework/Graphics/PerspectiveCamera.cs
Normal file
43
Blarg.GameFramework/Graphics/PerspectiveCamera.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
|
||||
namespace Blarg.GameFramework.Graphics
|
||||
{
|
||||
public class PerspectiveCamera : Camera
|
||||
{
|
||||
public float FieldOfViewAngle;
|
||||
|
||||
public PerspectiveCamera(ViewContext viewContext, float near = 1.0f, float far = 50.0f, float fieldOfView = MathConstants.Radians60)
|
||||
: base(viewContext, near, far)
|
||||
{
|
||||
FieldOfViewAngle = fieldOfView;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
CalculateProjection();
|
||||
CalculateLookAt();
|
||||
}
|
||||
|
||||
protected void CalculateLookAt()
|
||||
{
|
||||
var target = Position + Direction;
|
||||
Matrix4x4.CreateLookAt(ref Position, ref target, ref Up, out LookAt);
|
||||
ViewContext.ModelViewMatrix = LookAt;
|
||||
}
|
||||
|
||||
protected void CalculateProjection()
|
||||
{
|
||||
ViewportWidth = ViewContext.ViewportRight - ViewContext.ViewportLeft;
|
||||
ViewportHeight = ViewContext.ViewportBottom - ViewContext.ViewportTop;
|
||||
|
||||
float aspectRatio = (float)ViewportWidth / (float)ViewportHeight;
|
||||
|
||||
NearHeight = Near * (float)Math.Tan(FieldOfViewAngle / 2.0f);
|
||||
NearWidth = NearHeight * aspectRatio;
|
||||
|
||||
Matrix4x4.CreatePerspectiveFieldOfView(FieldOfViewAngle, aspectRatio, Near, Far, out Projection);
|
||||
ViewContext.ProjectionMatrix = Projection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ namespace Blarg.GameFramework.Graphics
|
|||
// not using the default camera, and clearing ("nulling") the camera
|
||||
else if (!_isUsingDefaultCamera && value == null)
|
||||
{
|
||||
_camera = new Camera(this);
|
||||
_camera = new PerspectiveCamera(this);
|
||||
_isUsingDefaultCamera = true;
|
||||
cameraWasChanged = true;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ namespace Blarg.GameFramework.Graphics
|
|||
_viewport = viewport;
|
||||
_viewportIsFixedSize = isFixedSizeViewport;
|
||||
_screenOrientation = ScreenOrientation.Rotation0;
|
||||
_camera = new Camera(this);
|
||||
_camera = new PerspectiveCamera(this);
|
||||
_isUsingDefaultCamera = true;
|
||||
_pixelScaler = new NoScaleOrthoPixelScaler();
|
||||
_isUsingDefaultPixelScaler = true;
|
||||
|
@ -207,18 +207,12 @@ namespace Blarg.GameFramework.Graphics
|
|||
public void OnRender(float delta)
|
||||
{
|
||||
if (_camera != null)
|
||||
_camera.OnRender(delta);
|
||||
_camera.Update();
|
||||
}
|
||||
|
||||
public void OnApply(ref Rect size, ScreenOrientation screenOrientation = ScreenOrientation.Rotation0)
|
||||
{
|
||||
SetupViewport(ref size, screenOrientation);
|
||||
|
||||
// ensures it's set up for rendering immediately when this call returns
|
||||
// NOTE: we assume OnApply() is going to be called in some other class's
|
||||
// OnRender() event only (like, e.g. if a new framebuffer is bound)
|
||||
if (_camera != null)
|
||||
_camera.OnRender(0.0f);
|
||||
}
|
||||
|
||||
private void SetupViewport(ref Rect size, ScreenOrientation screenOrientation)
|
||||
|
@ -257,7 +251,7 @@ namespace Blarg.GameFramework.Graphics
|
|||
|
||||
// we also **don't** want the camera to work with a rotated viewport
|
||||
if (_camera != null)
|
||||
_camera.OnResize(ref _viewport);
|
||||
_camera.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
using System;
|
||||
using Blarg.GameFramework.Graphics;
|
||||
using Blarg.GameFramework.Input;
|
||||
|
||||
namespace Blarg.GameFramework.Support
|
||||
{
|
||||
public class FreeMovementCamera : Camera
|
||||
{
|
||||
Vector3 _movement;
|
||||
|
||||
public FreeMovementCamera(ViewContext viewContext)
|
||||
: base(viewContext)
|
||||
{
|
||||
}
|
||||
|
||||
public void Move(float x, float y, float z)
|
||||
{
|
||||
Position = new Vector3(Position.X + x, Position.Y + y, Position.Z + z);
|
||||
}
|
||||
|
||||
public void Orient(float x, float y, float z)
|
||||
{
|
||||
Orientation = new Vector3(Orientation.X + x, Orientation.Y + y, Orientation.Z + z);
|
||||
}
|
||||
|
||||
public override void OnUpdate(float delta)
|
||||
{
|
||||
float pointerDeltaX = 0.0f;
|
||||
float pointerDeltaY = 0.0f;
|
||||
bool isPointerTouching = false;
|
||||
|
||||
if (Framework.Mouse != null && Framework.Mouse.IsDown(MouseButton.Left))
|
||||
{
|
||||
pointerDeltaX = Framework.Mouse.DeltaX;
|
||||
pointerDeltaY = Framework.Mouse.DeltaY;
|
||||
isPointerTouching = true;
|
||||
}
|
||||
else if (Framework.TouchScreen != null && Framework.TouchScreen.IsTouching)
|
||||
{
|
||||
pointerDeltaX = Framework.TouchScreen.PrimaryPointer.DeltaX;
|
||||
pointerDeltaY = Framework.TouchScreen.PrimaryPointer.DeltaY;
|
||||
isPointerTouching = true;
|
||||
}
|
||||
|
||||
|
||||
if (isPointerTouching)
|
||||
{
|
||||
var orientation = Orientation;
|
||||
|
||||
orientation.Y += pointerDeltaX * 0.01f;
|
||||
orientation.X += pointerDeltaY * 0.01f;
|
||||
|
||||
orientation.Y = MathHelpers.RolloverClamp(orientation.Y, MathConstants.Radians0, MathConstants.Radians360);
|
||||
orientation.X = MathHelpers.RolloverClamp(orientation.X, MathConstants.Radians0, MathConstants.Radians360);
|
||||
|
||||
Orientation = orientation;
|
||||
}
|
||||
|
||||
_movement = Vector3.Zero;
|
||||
|
||||
if (Framework.Keyboard.IsDown(Key.Up))
|
||||
_movement.Z -= delta * 6.0f;
|
||||
if (Framework.Keyboard.IsDown(Key.Down))
|
||||
_movement.Z += delta * 6.0f;
|
||||
if (Framework.Keyboard.IsDown(Key.Left))
|
||||
_movement.X -= delta * 6.0f;
|
||||
if (Framework.Keyboard.IsDown(Key.Right))
|
||||
_movement.X += delta * 6.0f;
|
||||
|
||||
UpdateLookAtMatrix(ref _movement);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ using Blarg.GameFramework.Events;
|
|||
using Blarg.GameFramework.Graphics;
|
||||
using Blarg.GameFramework.Graphics.Helpers;
|
||||
using Blarg.GameFramework.Graphics.ScreenEffects;
|
||||
using Blarg.GameFramework.Input;
|
||||
using Blarg.GameFramework.States;
|
||||
using Blarg.GameFramework.Support;
|
||||
|
||||
|
@ -12,7 +13,7 @@ namespace Game
|
|||
public class TestGameState : GameState
|
||||
{
|
||||
FlatWireframeGrid _grid;
|
||||
FreeMovementCamera _camera;
|
||||
EulerPerspectiveCamera _camera;
|
||||
|
||||
public TestGameState(StateManager stateManager, EventManager eventManager)
|
||||
: base(stateManager, eventManager)
|
||||
|
@ -21,7 +22,7 @@ namespace Game
|
|||
|
||||
public override void OnPush()
|
||||
{
|
||||
_camera = new FreeMovementCamera(Framework.GraphicsDevice.ViewContext);
|
||||
_camera = new EulerPerspectiveCamera(Framework.GraphicsDevice.ViewContext);
|
||||
_camera.Position = new Vector3(0.0f, 5.0f, 0.0f);
|
||||
Framework.GraphicsDevice.ViewContext.Camera = _camera;
|
||||
|
||||
|
@ -54,7 +55,46 @@ namespace Game
|
|||
base.OnUpdate(delta);
|
||||
if (Framework.Keyboard.IsPressed(Blarg.GameFramework.Input.Key.Escape))
|
||||
Framework.Application.Quit();
|
||||
_camera.OnUpdate(delta);
|
||||
|
||||
float pointerDeltaX = 0.0f;
|
||||
float pointerDeltaY = 0.0f;
|
||||
bool isPointerTouching = false;
|
||||
|
||||
if (Framework.Mouse != null && Framework.Mouse.IsDown(MouseButton.Left))
|
||||
{
|
||||
pointerDeltaX = Framework.Mouse.DeltaX;
|
||||
pointerDeltaY = Framework.Mouse.DeltaY;
|
||||
isPointerTouching = true;
|
||||
}
|
||||
else if (Framework.TouchScreen != null && Framework.TouchScreen.IsTouching)
|
||||
{
|
||||
pointerDeltaX = Framework.TouchScreen.PrimaryPointer.DeltaX;
|
||||
pointerDeltaY = Framework.TouchScreen.PrimaryPointer.DeltaY;
|
||||
isPointerTouching = true;
|
||||
}
|
||||
|
||||
|
||||
if (isPointerTouching)
|
||||
{
|
||||
_camera.Yaw += pointerDeltaX * 0.01f;
|
||||
_camera.Pitch += pointerDeltaY * 0.01f;
|
||||
|
||||
_camera.Pitch = MathHelpers.RolloverClamp(_camera.Pitch, MathConstants.Radians0, MathConstants.Radians360);
|
||||
_camera.Yaw = MathHelpers.RolloverClamp(_camera.Yaw, MathConstants.Radians0, MathConstants.Radians360);
|
||||
}
|
||||
|
||||
var movement = Vector3.Zero;
|
||||
|
||||
if (Framework.Keyboard.IsDown(Key.Up))
|
||||
movement.Z -= delta * 6.0f;
|
||||
if (Framework.Keyboard.IsDown(Key.Down))
|
||||
movement.Z += delta * 6.0f;
|
||||
if (Framework.Keyboard.IsDown(Key.Left))
|
||||
movement.X -= delta * 6.0f;
|
||||
if (Framework.Keyboard.IsDown(Key.Right))
|
||||
movement.X += delta * 6.0f;
|
||||
|
||||
_camera.Position += Quaternion.Transform(_camera.Rotation, movement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue