Merge pull request #2028 from Flakebi/fpscam

Improvements for the first person camera
This commit is contained in:
samuncle 2015-03-09 18:02:14 +01:00
commit 248755abee
5 changed files with 114 additions and 32 deletions

View File

@ -50,6 +50,7 @@ Camera* Camera::s_active_camera = NULL;
Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL)
{
m_smooth = false;
m_attached = false;
m_mode = CM_NORMAL;
m_index = camera_index;
m_original_kart = kart;
@ -91,6 +92,11 @@ Camera::Camera(int camera_index, AbstractKart* kart) : m_kart(NULL)
m_target_direction = core::vector3df(0, 0, 1);
m_target_up_vector = core::vector3df(0, 1, 0);
m_direction_velocity = core::vector3df(0, 0, 0);
m_local_position = core::vector3df(0, 0, 0);
m_local_direction = core::vector3df(0, 0, 1);
m_local_up = core::vector3df(0, 1, 0);
m_angular_velocity = 0;
m_target_angular_velocity = 0;
m_max_velocity = 15;
@ -108,6 +114,42 @@ Camera::~Camera()
s_active_camera = NULL;
} // ~Camera
//-----------------------------------------------------------------------------
/** Applies mouse movement to the first person camera.
* \param x The horizontal difference of the mouse position.
* \param y The vertical difference of the mouse position.
*/
void Camera::applyMouseMovement (float x, float y)
{
core::vector3df direction(m_target_direction);
core::vector3df up(m_camera->getUpVector());
// Set local values if the camera is attached to the kart
if (m_attached)
up = m_local_up;
core::vector3df side(direction.crossProduct(up));
direction.normalize();
up.normalize();
core::quaternion quat;
quat.fromAngleAxis(x, up);
core::quaternion quat_y;
quat_y.fromAngleAxis(y, side);
quat *= quat_y;
direction = quat * direction;
m_target_direction = direction;
// Don't do that because it looks ugly and is bad to handle ;)
/*side = direction.crossProduct(up);
// Compute new up vector
up = side.crossProduct(direction);
up.normalize();
cam->setUpVector(up);*/
}
//-----------------------------------------------------------------------------
/** Changes the owner of this camera to the new kart.
* \param new_kart The new kart to use this camera.
@ -489,11 +531,21 @@ void Camera::update(float dt)
// - the kart should not be visible, but it works)
m_camera->setNearValue(27.0);
}
// Update the first person camera
else if (UserConfigParams::m_camera_debug == 3)
{
core::vector3df direction(m_camera->getTarget() - m_camera->getPosition());
core::vector3df up(m_camera->getUpVector());
core::vector3df side(direction.crossProduct(up));
core::vector3df pos = m_camera->getPosition();
// Set local values if the camera is attached to the kart
if (m_attached)
{
direction = m_local_direction;
up = m_local_up;
pos = m_local_position;
}
// Update smooth movement
if (m_smooth)
@ -566,9 +618,33 @@ void Camera::update(float dt)
// Move camera
core::vector3df movement(direction * m_lin_velocity.Z +
up * m_lin_velocity.Y + side * m_lin_velocity.X);
core::vector3df pos = m_camera->getPosition();
pos = pos + movement * dt;
if (m_attached)
{
// Save current values
m_local_position = pos;
m_local_direction = direction;
m_local_up = up;
// Move the camera with the kart
btTransform t = m_kart->getTrans();
if (stk_config->m_camera_follow_skid &&
m_kart->getSkidding()->getVisualSkidRotation() != 0)
{
// If the camera should follow the graphical skid, add the
// visual rotation to the relative vector:
btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0);
t.setBasis(t.getBasis() * btMatrix3x3(q));
}
pos = Vec3(t(Vec3(pos))).toIrrVector();
btQuaternion q = t.getRotation();
btMatrix3x3 mat(q);
direction = Vec3(mat * Vec3(direction)).toIrrVector();
up = Vec3(mat * Vec3(up)).toIrrVector();
}
// Set camera attributes
m_camera->setPosition(pos);
m_camera->setTarget(pos + direction);

View File

@ -113,6 +113,10 @@ private:
/** Smooth acceleration with the first person camera. */
bool m_smooth;
/** Attache the first person camera to a kart.
That means moving the kart also moves the camera. */
bool m_attached;
/** The speed at which the up-vector rotates, only used for the first person camera. */
float m_angular_velocity;
@ -138,6 +142,15 @@ private:
/** The up vector the camera should have, only used for the first person camera. */
core::vector3df m_target_up_vector;
/** Save the local position if the first person camera is attached to the kart. */
core::vector3df m_local_position;
/** Save the local direction if the first person camera is attached to the kart. */
core::vector3df m_local_direction;
/** Save the local up vector if the first person camera is attached to the kart. */
core::vector3df m_local_up;
/** List of all cameras. */
static std::vector<Camera*> m_all_cameras;
@ -269,6 +282,10 @@ public:
/** Returns the kart to which this camera is attached. */
AbstractKart* getKart() { return m_kart; }
// ------------------------------------------------------------------------
/** Applies mouse movement to the first person camera. */
void applyMouseMovement (float x, float y);
// ------------------------------------------------------------------------
/** Sets if the first person camera should be moved smooth. */
void setSmoothMovement (bool value) { m_smooth = value; }
@ -277,6 +294,14 @@ public:
/** If the first person camera should be moved smooth. */
bool getSmoothMovement () { return m_smooth; }
// ------------------------------------------------------------------------
/** Sets if the first person camera should be moved with the kart. */
void setAttachedFpsCam (bool value) { m_attached = value; }
// ------------------------------------------------------------------------
/** If the first person camera should be moved with the kart. */
bool getAttachedFpsCam () { return m_attached; }
// ------------------------------------------------------------------------
/** Sets the angular velocity for this camera. */
void setMaximumVelocity (float vel) { m_max_velocity = vel; }

View File

@ -67,8 +67,7 @@ using GUIEngine::EVENT_BLOCK;
/** Initialise input
*/
InputManager::InputManager() : m_mode(BOOTSTRAP),
m_mouse_val_x(-1), m_mouse_val_y(-1),
m_mouse_reset(0)
m_mouse_val_x(-1), m_mouse_val_y(-1)
{
m_device_manager = new DeviceManager();
m_device_manager->initialize();
@ -977,34 +976,16 @@ EventPropagation InputManager::input(const SEvent& event)
UserConfigParams::m_fpscam_direction_speed;
float mouse_y = ((float) diff_y) *
-UserConfigParams::m_fpscam_direction_speed;
// No movement the first time it's used
// At the moment there's also a hard limit because the mouse
// gets reset to the middle of the screen and sometimes there
// are more events fired than expected.
if (m_mouse_val_x != -1 && m_mouse_reset <= 0)
if (m_mouse_val_x != -1 &&
(diff_x + diff_y) < 100 && (diff_x + diff_y) > -100)
{
// Rotate camera
core::vector3df up(cam->getUpVector());
core::vector3df direction(cam->getDirection());
core::vector3df side(direction.crossProduct(up));
direction.normalize();
up.normalize();
core::quaternion quat;
quat.fromAngleAxis(mouse_x, up);
core::quaternion quat_y;
quat_y.fromAngleAxis(mouse_y, side);
quat *= quat_y;
direction = quat * direction;
cam->setDirection(direction);
side = direction.crossProduct(up);
// Compute new up vector
/*up = side.crossProduct(direction);
up.normalize();
// Don't do that because it looks ugly and is bad to handle ;)
cam->setUpVector(up);*/
cam->applyMouseMovement(mouse_x, mouse_y);
// Reset mouse position to the middle of the screen when
// the mouse is far away
@ -1016,8 +997,6 @@ EventPropagation InputManager::input(const SEvent& event)
irr_driver->getDevice()->getCursorControl()->setPosition(mid_x, mid_y);
m_mouse_val_x = mid_x;
m_mouse_val_y = mid_y;
// Ignore the next 2 movements
m_mouse_reset = 2;
}
else
{
@ -1029,7 +1008,6 @@ EventPropagation InputManager::input(const SEvent& event)
{
m_mouse_val_x = event.MouseInput.X;
m_mouse_val_y = event.MouseInput.Y;
--m_mouse_reset;
}
return EVENT_BLOCK;
}

View File

@ -67,10 +67,6 @@ private:
* makes the mouse behave like an analog axis on a gamepad/joystick.
*/
int m_mouse_val_x, m_mouse_val_y;
/** To detect mouse events that are not caused by the user but by resetting
the mouse position to the center of the screen.
If it's not 0, the movement is ignored and the value is decreased. */
int m_mouse_reset;
void dispatchInput(Input::InputType, int deviceID, int btnID,
Input::AxisDirection direction, int value);

View File

@ -97,6 +97,7 @@ enum DebugMenuCommand
DEBUG_GUI_CAM_WHEEL,
DEBUG_GUI_CAM_NORMAL,
DEBUG_GUI_CAM_SMOOTH,
DEBUG_GUI_CAM_ATTACH,
DEBUG_HIDE_KARTS,
DEBUG_THROTTLE_FPS,
DEBUG_VISUAL_VALUES,
@ -260,6 +261,7 @@ bool onEvent(const SEvent &event)
sub->addItem(L"First person view", DEBUG_GUI_CAM_FREE);
sub->addItem(L"Normal view", DEBUG_GUI_CAM_NORMAL);
sub->addItem(L"Toggle smooth camera", DEBUG_GUI_CAM_SMOOTH);
sub->addItem(L"Attach fps camera to kart", DEBUG_GUI_CAM_ATTACH);
mnu->addItem(L"Adjust values", DEBUG_VISUAL_VALUES);
@ -539,6 +541,11 @@ bool onEvent(const SEvent &event)
Camera *cam = Camera::getActiveCamera();
cam->setSmoothMovement(!cam->getSmoothMovement());
}
else if (cmdID == DEBUG_GUI_CAM_ATTACH)
{
Camera *cam = Camera::getActiveCamera();
cam->setAttachedFpsCam(!cam->getAttachedFpsCam());
}
else if (cmdID == DEBUG_PRINT_START_POS)
{
if(!world) return false;