2 // Copyright (c) Microsoft. All rights reserved.
3 // This code is licensed under the MIT License (MIT).
4 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
5 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
6 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
7 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
9 // Developed by Minigraph
11 // Author: James Stanard
15 #include "CameraController.h"
17 #include "GameInput.h"
20 using namespace GameCore
;
22 CameraController::CameraController( Camera
& camera
, Vector3 worldUp
) : m_TargetCamera( camera
)
24 m_WorldUp
= Normalize(worldUp
);
25 m_WorldNorth
= Normalize(Cross(m_WorldUp
, Vector3(kXUnitVector
)));
26 m_WorldEast
= Cross(m_WorldNorth
, m_WorldUp
);
28 m_HorizontalLookSensitivity
= 2.0f
;
29 m_VerticalLookSensitivity
= 2.0f
;
30 m_MoveSpeed
= 1000.0f
;
31 m_StrafeSpeed
= 1000.0f
;
32 m_MouseSensitivityX
= 1.0f
;
33 m_MouseSensitivityY
= 1.0f
;
35 m_CurrentPitch
= Sin(Dot(camera
.GetForwardVec(), m_WorldUp
));
37 Vector3 forward
= Normalize(Cross(m_WorldUp
, camera
.GetRightVec()));
38 m_CurrentHeading
= ATan2(-Dot(forward
, m_WorldEast
), Dot(forward
, m_WorldNorth
));
40 m_FineMovement
= false;
41 m_FineRotation
= false;
53 extern EnumVar DebugZoom
;
56 void CameraController::Update( float deltaTime
)
58 float timeScale
= Graphics::DebugZoom
== 0 ? 1.0f
: Graphics::DebugZoom
== 1 ? 0.5f
: 0.25f
;
60 if (GameInput::IsFirstPressed(GameInput::kLThumbClick
) || GameInput::IsFirstPressed(GameInput::kKey_lshift
))
61 m_FineMovement
= !m_FineMovement
;
63 if (GameInput::IsFirstPressed(GameInput::kRThumbClick
))
64 m_FineRotation
= !m_FineRotation
;
66 float speedScale
= (m_FineMovement
? 0.1f
: 1.0f
) * timeScale
;
67 float panScale
= (m_FineRotation
? 0.5f
: 1.0f
) * timeScale
;
69 float yaw
= GameInput::GetTimeCorrectedAnalogInput( GameInput::kAnalogRightStickX
) * m_HorizontalLookSensitivity
* panScale
;
70 float pitch
= GameInput::GetTimeCorrectedAnalogInput( GameInput::kAnalogRightStickY
) * m_VerticalLookSensitivity
* panScale
;
71 float forward
= m_MoveSpeed
* speedScale
* (
72 GameInput::GetTimeCorrectedAnalogInput( GameInput::kAnalogLeftStickY
) +
73 (GameInput::IsPressed( GameInput::kKey_w
) ? deltaTime
: 0.0f
) +
74 (GameInput::IsPressed( GameInput::kKey_s
) ? -deltaTime
: 0.0f
)
76 float strafe
= m_StrafeSpeed
* speedScale
* (
77 GameInput::GetTimeCorrectedAnalogInput( GameInput::kAnalogLeftStickX
) +
78 (GameInput::IsPressed( GameInput::kKey_d
) ? deltaTime
: 0.0f
) +
79 (GameInput::IsPressed( GameInput::kKey_a
) ? -deltaTime
: 0.0f
)
81 float ascent
= m_StrafeSpeed
* speedScale
* (
82 GameInput::GetTimeCorrectedAnalogInput( GameInput::kAnalogRightTrigger
) -
83 GameInput::GetTimeCorrectedAnalogInput( GameInput::kAnalogLeftTrigger
) +
84 (GameInput::IsPressed( GameInput::kKey_e
) ? deltaTime
: 0.0f
) +
85 (GameInput::IsPressed( GameInput::kKey_q
) ? -deltaTime
: 0.0f
)
90 ApplyMomentum(m_LastYaw
, yaw
, deltaTime
);
91 ApplyMomentum(m_LastPitch
, pitch
, deltaTime
);
92 ApplyMomentum(m_LastForward
, forward
, deltaTime
);
93 ApplyMomentum(m_LastStrafe
, strafe
, deltaTime
);
94 ApplyMomentum(m_LastAscent
, ascent
, deltaTime
);
97 // don't apply momentum to mouse inputs
98 yaw
+= GameInput::GetAnalogInput(GameInput::kAnalogMouseX
) * m_MouseSensitivityX
;
99 pitch
+= GameInput::GetAnalogInput(GameInput::kAnalogMouseY
) * m_MouseSensitivityY
;
101 m_CurrentPitch
+= pitch
;
102 m_CurrentPitch
= XMMin( XM_PIDIV2
, m_CurrentPitch
);
103 m_CurrentPitch
= XMMax(-XM_PIDIV2
, m_CurrentPitch
);
105 m_CurrentHeading
-= yaw
;
106 if (m_CurrentHeading
> XM_PI
)
107 m_CurrentHeading
-= XM_2PI
;
108 else if (m_CurrentHeading
<= -XM_PI
)
109 m_CurrentHeading
+= XM_2PI
;
111 Matrix3 orientation
= Matrix3(m_WorldEast
, m_WorldUp
, -m_WorldNorth
) * Matrix3::MakeYRotation( m_CurrentHeading
) * Matrix3::MakeXRotation( m_CurrentPitch
);
112 Vector3 position
= orientation
* Vector3( strafe
, ascent
, -forward
) + m_TargetCamera
.GetPosition();
113 m_TargetCamera
.SetTransform( AffineTransform( orientation
, position
) );
114 m_TargetCamera
.Update();
117 void CameraController::ApplyMomentum( float& oldValue
, float& newValue
, float deltaTime
)
120 if (Abs(newValue
) > Abs(oldValue
))
121 blendedValue
= Lerp(newValue
, oldValue
, Pow(0.6f
, deltaTime
* 60.0f
));
123 blendedValue
= Lerp(newValue
, oldValue
, Pow(0.8f
, deltaTime
* 60.0f
));
124 oldValue
= blendedValue
;
125 newValue
= blendedValue
;