1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 02:12:45 +01:00

Overhaul camera behaviour

This commit is contained in:
Daniel Evans 2015-05-04 04:35:22 +01:00
parent 8b18712d1f
commit f9ce9a2057
2 changed files with 52 additions and 83 deletions

View File

@ -102,48 +102,29 @@ void IngameState::tick(float dt)
{
float qpi = glm::half_pi<float>();
sf::Vector2i screenCenter{sf::Vector2i{getWindow().getSize()} / 2};
sf::Vector2i mousePos = sf::Mouse::getPosition(getWindow());
sf::Vector2i deltaMouse = mousePos - screenCenter;
sf::Mouse::setPosition(screenCenter, getWindow());
sf::Vector2f screenSize(getWindow().getSize());
sf::Vector2f screenCenter(screenSize / 2.f);
sf::Vector2f mousePos(sf::Mouse::getPosition(getWindow()));
sf::Vector2f deltaMouse = (mousePos - screenCenter);
sf::Vector2f mouseMove(deltaMouse.x / screenSize.x, deltaMouse.y / screenSize.y);
sf::Mouse::setPosition(sf::Vector2i(screenCenter), getWindow());
if(deltaMouse.x != 0 || deltaMouse.y != 0)
{
autolookTimer = AUTOLOOK_TIME;
}
_lookAngles.x += deltaMouse.x / 100.0;
_lookAngles.y += deltaMouse.y / 100.0;
while(_lookAngles.x > glm::pi<float>())
{
_lookAngles.x -= 2.f * glm::pi<float>();
}
while(_lookAngles.x < -glm::pi<float>())
{
_lookAngles.x += 2.f * glm::pi<float>();
}
if (_lookAngles.y > qpi)
_lookAngles.y = qpi;
else if (_lookAngles.y < -qpi)
_lookAngles.y = -qpi;
auto angle = glm::angleAxis(-_lookAngles.x, glm::vec3(0.f, 0.f, 1.f));
angle *= glm::angleAxis(_lookAngles.y, glm::vec3(0.f, 1.f, 0.f));
player->updateMovementDirection(angle * _movement, _movement);
float viewDistance = 4.f;
auto target = getWorld()->findObject(getWorld()->state->cameraTarget);
if( target == nullptr )
{
target = player->getCharacter();
}
auto position = target->getPosition();
glm::vec3 targetPosition = target->getPosition();
targetPosition += glm::vec3(0.f, 0.f, 1.f);
float viewDistance = 4.f;
btCollisionObject* physTarget = player->getCharacter()->physObject;
auto vehicle = ( target->type() == GameObject::Character ) ? static_cast<CharacterObject*>(target)->getCurrentVehicle() : nullptr;
@ -154,50 +135,47 @@ void IngameState::tick(float dt)
(glm::length(g->geometryBounds.center) + g->geometryBounds.radius) * 4.0f,
viewDistance);
}
position = vehicle->getPosition();
position.z += (vehicle->info->handling.dimensions.z / 2.f) * 2.5f;
targetPosition = vehicle->getPosition();
targetPosition.z += (vehicle->info->handling.dimensions.z / 2.f) * 2.0f;
physTarget = vehicle->physBody;
float speed = vehicle->physVehicle->getCurrentSpeedKmHour();
if( autolookTimer <= 0.f && std::abs(speed) > 1.f )
{
float b = glm::roll(vehicle->getRotation()) + glm::half_pi<float>();
while( b > glm::pi<float>() )
{
b -= 2.f * glm::pi<float>();
}
while( b < -glm::pi<float>() )
{
b += 2.f * glm::pi<float>();
}
if( speed < 0.f )
{
if( _lookAngles.x < 0.f )
{
b -= glm::pi<float>();
}
else
{
b += glm::pi<float>();
}
}
float aD = b - _lookAngles.x;
const float rotateSpeed = 1.f;
if( std::abs(aD) <= rotateSpeed * dt )
{
_lookAngles.x = b;
}
else
{
_lookAngles.x += glm::sign(aD) * rotateSpeed * dt;
}
angle = glm::angleAxis(_lookAngles.x, glm::vec3(0.f, 0.f, 1.f));
}
}
auto rayEnd = position + angle * glm::vec3(-viewDistance, 0.f, 1.f);
auto rayStart = position + glm::vec3(0.f, 0.f, 1.f);
{
// Rotate the cameraPosition vector around targetPosition by the mouse movement
auto camtotarget = targetPosition - cameraPosition;
float camAngle = glm::atan(camtotarget.y, camtotarget.x);
glm::quat epsilon( glm::vec3( 0.f, 0.f, camAngle) );
glm::quat theta( glm::vec3(0.f, 0.f, -mouseMove.x) );
glm::quat rho( epsilon * glm::vec3(0.f, mouseMove.y, 0.f) );
cameraPosition = targetPosition - (theta * (rho * camtotarget));
}
glm::quat angle;
auto camtotarget = targetPosition - cameraPosition;
auto dir = glm::normalize(camtotarget);
float correction = glm::length(camtotarget) - viewDistance;
if( correction < 0.f )
{
float innerDist = viewDistance * 0.25f;
correction = glm::min(0.f, correction + innerDist);
}
cameraPosition += dir * 10.f * correction * dt;
// Calculate the yaw to look at the target.
float angleYaw = glm::atan(dir.y, dir.x);
angle = glm::quat( glm::vec3(0.f, 0.f, angleYaw) );
// Update player with camera yaw
player->updateMovementDirection(angle * _movement, _movement);
float len2d = glm::length(glm::vec2(dir));
float anglePitch = glm::atan(dir.z, len2d);
angle *= glm::quat( glm::vec3(0.f, -anglePitch, 0.f) );
// Use rays to ensure target is visible from cameraPosition
auto rayEnd = cameraPosition;
auto rayStart = targetPosition;
auto to = btVector3(rayEnd.x, rayEnd.y, rayEnd.z);
auto from = btVector3(rayStart.x, rayStart.y, rayStart.z);
ClosestNotMeRayResultCallback ray(physTarget, from, to);
@ -205,22 +183,13 @@ void IngameState::tick(float dt)
getWorld()->dynamicsWorld->rayTest(from, to, ray);
if( ray.hasHit() && ray.m_closestHitFraction < 1.f )
{
position = glm::vec3(ray.m_hitPointWorld.x(), ray.m_hitPointWorld.y(),
cameraPosition = glm::vec3(ray.m_hitPointWorld.x(), ray.m_hitPointWorld.y(),
ray.m_hitPointWorld.z());
position += glm::vec3(ray.m_hitNormalWorld.x(), ray.m_hitNormalWorld.y(),
cameraPosition += glm::vec3(ray.m_hitNormalWorld.x(), ray.m_hitNormalWorld.y(),
ray.m_hitNormalWorld.z()) * 0.1f;
}
else
{
position = rayEnd;
}
// Move back from the character
// Tilt the final look angle down a tad.
angle *= glm::angleAxis(glm::radians(10.f), glm::vec3(0.f, 1.f, 0.f));
_look.position = position;
_look.position = cameraPosition;
_look.rotation = angle;
}
}

View File

@ -12,8 +12,8 @@ class IngameState : public State
bool newgame;
ViewCamera _look;
/** Player input */
glm::vec2 _lookAngles;
glm::vec3 _movement;
glm::vec3 cameraPosition;
/** Timer to reset _lookAngles to forward in vehicles */
float autolookTimer;
public: